awaitly-postgres 0.1.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/README.md ADDED
@@ -0,0 +1,139 @@
1
+ # awaitly-postgres
2
+
3
+ PostgreSQL persistence adapter for [awaitly](https://github.com/jagreehal/awaitly) workflows.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install awaitly-postgres pg
9
+ # or
10
+ pnpm add awaitly-postgres pg
11
+ # or
12
+ yarn add awaitly-postgres pg
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ```typescript
18
+ import { createPostgresPersistence } from 'awaitly-postgres';
19
+ import { durable } from 'awaitly/durable';
20
+
21
+ const store = await createPostgresPersistence({
22
+ connectionString: process.env.DATABASE_URL,
23
+ });
24
+
25
+ const result = await durable.run(
26
+ { fetchUser, createOrder },
27
+ async (step, { fetchUser, createOrder }) => {
28
+ const user = await step(() => fetchUser('123'), { key: 'fetch-user' });
29
+ const order = await step(() => createOrder(user), { key: 'create-order' });
30
+ return order;
31
+ },
32
+ {
33
+ id: 'checkout-123',
34
+ store,
35
+ }
36
+ );
37
+ ```
38
+
39
+ ## Configuration
40
+
41
+ ### Connection String
42
+
43
+ ```typescript
44
+ const store = await createPostgresPersistence({
45
+ connectionString: 'postgresql://user:password@localhost:5432/dbname',
46
+ });
47
+ ```
48
+
49
+ ### Individual Options
50
+
51
+ ```typescript
52
+ const store = await createPostgresPersistence({
53
+ host: 'localhost',
54
+ port: 5432,
55
+ database: 'myapp',
56
+ user: 'postgres',
57
+ password: 'password',
58
+ tableName: 'custom_workflow_state', // optional, default: 'awaitly_workflow_state'
59
+ prefix: 'myapp:workflow:', // optional, default: 'workflow:state:'
60
+ });
61
+ ```
62
+
63
+ ### Using Existing Pool
64
+
65
+ ```typescript
66
+ import { Pool } from 'pg';
67
+ import { createPostgresPersistence } from 'awaitly-postgres';
68
+
69
+ const pool = new Pool({ connectionString: process.env.DATABASE_URL });
70
+ const store = await createPostgresPersistence({
71
+ existingPool: pool,
72
+ });
73
+ ```
74
+
75
+ ### Pool Configuration
76
+
77
+ ```typescript
78
+ const store = await createPostgresPersistence({
79
+ connectionString: process.env.DATABASE_URL,
80
+ pool: {
81
+ max: 20,
82
+ idleTimeoutMillis: 30000,
83
+ connectionTimeoutMillis: 2000,
84
+ },
85
+ });
86
+ ```
87
+
88
+ ## Table Schema
89
+
90
+ The adapter automatically creates a table with the following schema:
91
+
92
+ ```sql
93
+ CREATE TABLE awaitly_workflow_state (
94
+ key TEXT PRIMARY KEY,
95
+ value TEXT NOT NULL,
96
+ expires_at TIMESTAMP
97
+ );
98
+
99
+ CREATE INDEX idx_awaitly_workflow_state_expires_at
100
+ ON awaitly_workflow_state(expires_at)
101
+ WHERE expires_at IS NOT NULL;
102
+ ```
103
+
104
+ The table is created automatically on first use. You can customize the table name via the `tableName` option.
105
+
106
+ ## Advanced Usage
107
+
108
+ ### Direct KeyValueStore Access
109
+
110
+ If you need more control, you can use the `PostgresKeyValueStore` class directly:
111
+
112
+ ```typescript
113
+ import { PostgresKeyValueStore } from 'awaitly-postgres';
114
+ import { createStatePersistence } from 'awaitly/persistence';
115
+
116
+ const store = new PostgresKeyValueStore({
117
+ connectionString: process.env.DATABASE_URL,
118
+ });
119
+
120
+ const persistence = createStatePersistence(store, 'custom:prefix:');
121
+ ```
122
+
123
+ ## Features
124
+
125
+ - ✅ Automatic table creation
126
+ - ✅ TTL support (automatic expiration)
127
+ - ✅ Connection pooling
128
+ - ✅ Pattern matching for key queries
129
+ - ✅ Zero configuration required
130
+
131
+ ## Requirements
132
+
133
+ - Node.js >= 22
134
+ - PostgreSQL >= 12
135
+ - `pg` package (peer dependency)
136
+
137
+ ## License
138
+
139
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,35 @@
1
+ "use strict";var n=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var c=Object.getOwnPropertyNames;var y=Object.prototype.hasOwnProperty;var g=(r,e)=>{for(var t in e)n(r,t,{get:e[t],enumerable:!0})},P=(r,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of c(e))!y.call(r,s)&&s!==t&&n(r,s,{get:()=>e[s],enumerable:!(i=p(e,s))||i.enumerable});return r};var m=r=>P(n({},"__esModule",{value:!0}),r);var E={};g(E,{PostgresKeyValueStore:()=>a,createPostgresPersistence:()=>h});module.exports=m(E);var l=require("pg"),a=class{pool;tableName;initialized=!1;initPromise=null;constructor(e){e.existingPool?this.pool=e.existingPool:e.connectionString?this.pool=new l.Pool({connectionString:e.connectionString,...e.pool}):this.pool=new l.Pool({host:e.host??"localhost",port:e.port??5432,database:e.database,user:e.user,password:e.password,...e.pool}),this.tableName=e.tableName??"awaitly_workflow_state"}async ensureInitialized(){if(!this.initialized)return this.initPromise?this.initPromise:(this.initPromise=(async()=>{try{await this.createTable(),this.initialized=!0}catch(e){throw this.initPromise=null,e}})(),this.initPromise)}async createTable(){let e=`
2
+ CREATE TABLE IF NOT EXISTS ${this.tableName} (
3
+ key TEXT PRIMARY KEY,
4
+ value TEXT NOT NULL,
5
+ expires_at TIMESTAMP
6
+ );
7
+
8
+ CREATE INDEX IF NOT EXISTS idx_${this.tableName}_expires_at
9
+ ON ${this.tableName}(expires_at)
10
+ WHERE expires_at IS NOT NULL;
11
+ `;await this.pool.query(e)}patternToLike(e){return e.replace(/%/g,"\\%").replace(/_/g,"\\_").replace(/\*/g,"%")}async get(e){await this.ensureInitialized();let t=`
12
+ SELECT value
13
+ FROM ${this.tableName}
14
+ WHERE key = $1
15
+ AND (expires_at IS NULL OR expires_at > NOW())
16
+ `,i=await this.pool.query(t,[e]);return i.rows.length===0?null:i.rows[0].value}async set(e,t,i){await this.ensureInitialized();let s=i?.ttl?new Date(Date.now()+i.ttl*1e3):null,o=`
17
+ INSERT INTO ${this.tableName} (key, value, expires_at)
18
+ VALUES ($1, $2, $3)
19
+ ON CONFLICT (key)
20
+ DO UPDATE SET
21
+ value = EXCLUDED.value,
22
+ expires_at = EXCLUDED.expires_at
23
+ `;await this.pool.query(o,[e,t,s])}async delete(e){await this.ensureInitialized();let t=`DELETE FROM ${this.tableName} WHERE key = $1`;return((await this.pool.query(t,[e])).rowCount??0)>0}async exists(e){await this.ensureInitialized();let t=`
24
+ SELECT 1
25
+ FROM ${this.tableName}
26
+ WHERE key = $1
27
+ AND (expires_at IS NULL OR expires_at > NOW())
28
+ LIMIT 1
29
+ `;return(await this.pool.query(t,[e])).rows.length>0}async keys(e){await this.ensureInitialized();let t=this.patternToLike(e),i=`
30
+ SELECT key
31
+ FROM ${this.tableName}
32
+ WHERE key LIKE $1
33
+ AND (expires_at IS NULL OR expires_at > NOW())
34
+ `;return(await this.pool.query(i,[t])).rows.map(o=>o.key)}async close(){await this.pool.end()}};var u=require("awaitly/persistence");async function h(r={}){let{prefix:e,...t}=r,i=new a(t);return(0,u.createStatePersistence)(i,e)}0&&(module.exports={PostgresKeyValueStore,createPostgresPersistence});
35
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/postgres-store.ts"],"sourcesContent":["/**\n * awaitly-postgres\n *\n * PostgreSQL persistence adapter for awaitly workflows.\n * Provides ready-to-use StatePersistence backed by PostgreSQL.\n */\n\nimport { PostgresKeyValueStore, type PostgresKeyValueStoreOptions } from \"./postgres-store\";\nimport { createStatePersistence, type StatePersistence } from \"awaitly/persistence\";\n\n/**\n * Options for creating PostgreSQL persistence.\n */\nexport interface PostgresPersistenceOptions extends PostgresKeyValueStoreOptions {\n /**\n * Key prefix for state entries.\n * @default 'workflow:state:'\n */\n prefix?: string;\n}\n\n/**\n * Create a StatePersistence instance backed by PostgreSQL.\n *\n * The table is automatically created on first use.\n *\n * @param options - PostgreSQL connection and configuration options\n * @returns StatePersistence instance ready to use with durable.run()\n *\n * @example\n * ```typescript\n * import { createPostgresPersistence } from 'awaitly-postgres';\n * import { durable } from 'awaitly/durable';\n *\n * const store = await createPostgresPersistence({\n * connectionString: process.env.DATABASE_URL,\n * });\n *\n * const result = await durable.run(\n * { fetchUser, createOrder },\n * async (step, { fetchUser, createOrder }) => {\n * const user = await step(() => fetchUser('123'), { key: 'fetch-user' });\n * const order = await step(() => createOrder(user), { key: 'create-order' });\n * return order;\n * },\n * {\n * id: 'checkout-123',\n * store,\n * }\n * );\n * ```\n *\n * @example\n * ```typescript\n * // Using individual connection options\n * const store = await createPostgresPersistence({\n * host: 'localhost',\n * port: 5432,\n * database: 'myapp',\n * user: 'postgres',\n * password: 'password',\n * tableName: 'custom_workflow_state',\n * });\n * ```\n */\nexport async function createPostgresPersistence(\n options: PostgresPersistenceOptions = {}\n): Promise<StatePersistence & { loadRaw(runId: string): Promise<import(\"awaitly/persistence\").SerializedState | undefined> }> {\n const { prefix, ...storeOptions } = options;\n\n const store = new PostgresKeyValueStore(storeOptions);\n return createStatePersistence(store, prefix);\n}\n\n/**\n * PostgreSQL KeyValueStore implementation.\n * Use this directly if you need more control over the store.\n *\n * @example\n * ```typescript\n * import { PostgresKeyValueStore } from 'awaitly-postgres';\n * import { createStatePersistence } from 'awaitly/persistence';\n *\n * const store = new PostgresKeyValueStore({\n * connectionString: process.env.DATABASE_URL,\n * });\n *\n * const persistence = createStatePersistence(store, 'custom:prefix:');\n * ```\n */\nexport { PostgresKeyValueStore, type PostgresKeyValueStoreOptions };\n","/**\n * awaitly-postgres\n *\n * PostgreSQL KeyValueStore implementation for awaitly persistence.\n */\n\nimport type { Pool, PoolConfig, QueryResult } from \"pg\";\nimport { Pool as PgPool } from \"pg\";\nimport type { KeyValueStore } from \"awaitly/persistence\";\n\n/**\n * Options for PostgreSQL KeyValueStore.\n */\nexport interface PostgresKeyValueStoreOptions {\n /**\n * PostgreSQL connection string.\n * If provided, other connection options are ignored.\n *\n * @example 'postgresql://user:password@localhost:5432/dbname'\n */\n connectionString?: string;\n\n /**\n * Database host.\n * @default 'localhost'\n */\n host?: string;\n\n /**\n * Database port.\n * @default 5432\n */\n port?: number;\n\n /**\n * Database name.\n */\n database?: string;\n\n /**\n * Database user.\n */\n user?: string;\n\n /**\n * Database password.\n */\n password?: string;\n\n /**\n * Table name for storing key-value pairs.\n * @default 'awaitly_workflow_state'\n */\n tableName?: string;\n\n /**\n * Additional pool configuration options.\n * Ignored if `existingPool` is provided.\n */\n pool?: PoolConfig;\n\n /**\n * Existing PostgreSQL pool to use.\n * If provided, connection options are ignored.\n */\n existingPool?: Pool;\n}\n\n/**\n * PostgreSQL implementation of KeyValueStore.\n *\n * Automatically creates the required table on first use.\n * Supports TTL via expires_at column.\n */\nexport class PostgresKeyValueStore implements KeyValueStore {\n private pool: Pool;\n private tableName: string;\n private initialized: boolean = false;\n private initPromise: Promise<void> | null = null;\n\n constructor(options: PostgresKeyValueStoreOptions) {\n if (options.existingPool) {\n // Use provided pool\n this.pool = options.existingPool;\n } else if (options.connectionString) {\n // Create pool from connection string\n this.pool = new PgPool({\n connectionString: options.connectionString,\n ...options.pool,\n });\n } else {\n // Create pool from individual options\n this.pool = new PgPool({\n host: options.host ?? \"localhost\",\n port: options.port ?? 5432,\n database: options.database,\n user: options.user,\n password: options.password,\n ...options.pool,\n });\n }\n\n this.tableName = options.tableName ?? \"awaitly_workflow_state\";\n }\n\n /**\n * Initialize the store by creating the table if it doesn't exist.\n * This is called automatically on first use.\n */\n private async ensureInitialized(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n if (this.initPromise) {\n return this.initPromise;\n }\n\n this.initPromise = (async () => {\n try {\n await this.createTable();\n this.initialized = true;\n } catch (error) {\n this.initPromise = null;\n throw error;\n }\n })();\n\n return this.initPromise;\n }\n\n /**\n * Create the table if it doesn't exist.\n */\n private async createTable(): Promise<void> {\n const query = `\n CREATE TABLE IF NOT EXISTS ${this.tableName} (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL,\n expires_at TIMESTAMP\n );\n\n CREATE INDEX IF NOT EXISTS idx_${this.tableName}_expires_at \n ON ${this.tableName}(expires_at) \n WHERE expires_at IS NOT NULL;\n `;\n\n await this.pool.query(query);\n }\n\n /**\n * Convert glob pattern to SQL LIKE pattern.\n * Supports * wildcard (matches any characters).\n */\n private patternToLike(pattern: string): string {\n // Escape SQL LIKE special characters and convert * to %\n return pattern.replace(/%/g, \"\\\\%\").replace(/_/g, \"\\\\_\").replace(/\\*/g, \"%\");\n }\n\n async get(key: string): Promise<string | null> {\n await this.ensureInitialized();\n\n const query = `\n SELECT value \n FROM ${this.tableName} \n WHERE key = $1 \n AND (expires_at IS NULL OR expires_at > NOW())\n `;\n\n const result: QueryResult<{ value: string }> = await this.pool.query(query, [key]);\n\n if (result.rows.length === 0) {\n return null;\n }\n\n return result.rows[0].value;\n }\n\n async set(key: string, value: string, options?: { ttl?: number }): Promise<void> {\n await this.ensureInitialized();\n\n const expiresAt = options?.ttl\n ? new Date(Date.now() + options.ttl * 1000)\n : null;\n\n const query = `\n INSERT INTO ${this.tableName} (key, value, expires_at)\n VALUES ($1, $2, $3)\n ON CONFLICT (key) \n DO UPDATE SET \n value = EXCLUDED.value,\n expires_at = EXCLUDED.expires_at\n `;\n\n await this.pool.query(query, [key, value, expiresAt]);\n }\n\n async delete(key: string): Promise<boolean> {\n await this.ensureInitialized();\n\n const query = `DELETE FROM ${this.tableName} WHERE key = $1`;\n const result = await this.pool.query(query, [key]);\n\n return (result.rowCount ?? 0) > 0;\n }\n\n async exists(key: string): Promise<boolean> {\n await this.ensureInitialized();\n\n const query = `\n SELECT 1 \n FROM ${this.tableName} \n WHERE key = $1 \n AND (expires_at IS NULL OR expires_at > NOW())\n LIMIT 1\n `;\n\n const result = await this.pool.query(query, [key]);\n return result.rows.length > 0;\n }\n\n async keys(pattern: string): Promise<string[]> {\n await this.ensureInitialized();\n\n // Convert glob pattern to SQL LIKE\n const likePattern = this.patternToLike(pattern);\n\n const query = `\n SELECT key \n FROM ${this.tableName} \n WHERE key LIKE $1 \n AND (expires_at IS NULL OR expires_at > NOW())\n `;\n\n const result: QueryResult<{ key: string }> = await this.pool.query(query, [likePattern]);\n\n return result.rows.map((row) => row.key);\n }\n\n /**\n * Close the database connection pool.\n * Call this when done with the store.\n */\n async close(): Promise<void> {\n await this.pool.end();\n }\n}\n"],"mappings":"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","names":["index_exports","__export","PostgresKeyValueStore","createPostgresPersistence","__toCommonJS","import_pg","PostgresKeyValueStore","options","PgPool","error","query","pattern","key","result","value","expiresAt","likePattern","row","import_persistence","createPostgresPersistence","options","prefix","storeOptions","store","PostgresKeyValueStore"]}
@@ -0,0 +1,158 @@
1
+ import * as awaitly_persistence from 'awaitly/persistence';
2
+ import { KeyValueStore, StatePersistence } from 'awaitly/persistence';
3
+ import { PoolConfig, Pool } from 'pg';
4
+
5
+ /**
6
+ * awaitly-postgres
7
+ *
8
+ * PostgreSQL KeyValueStore implementation for awaitly persistence.
9
+ */
10
+
11
+ /**
12
+ * Options for PostgreSQL KeyValueStore.
13
+ */
14
+ interface PostgresKeyValueStoreOptions {
15
+ /**
16
+ * PostgreSQL connection string.
17
+ * If provided, other connection options are ignored.
18
+ *
19
+ * @example 'postgresql://user:password@localhost:5432/dbname'
20
+ */
21
+ connectionString?: string;
22
+ /**
23
+ * Database host.
24
+ * @default 'localhost'
25
+ */
26
+ host?: string;
27
+ /**
28
+ * Database port.
29
+ * @default 5432
30
+ */
31
+ port?: number;
32
+ /**
33
+ * Database name.
34
+ */
35
+ database?: string;
36
+ /**
37
+ * Database user.
38
+ */
39
+ user?: string;
40
+ /**
41
+ * Database password.
42
+ */
43
+ password?: string;
44
+ /**
45
+ * Table name for storing key-value pairs.
46
+ * @default 'awaitly_workflow_state'
47
+ */
48
+ tableName?: string;
49
+ /**
50
+ * Additional pool configuration options.
51
+ * Ignored if `existingPool` is provided.
52
+ */
53
+ pool?: PoolConfig;
54
+ /**
55
+ * Existing PostgreSQL pool to use.
56
+ * If provided, connection options are ignored.
57
+ */
58
+ existingPool?: Pool;
59
+ }
60
+ /**
61
+ * PostgreSQL implementation of KeyValueStore.
62
+ *
63
+ * Automatically creates the required table on first use.
64
+ * Supports TTL via expires_at column.
65
+ */
66
+ declare class PostgresKeyValueStore implements KeyValueStore {
67
+ private pool;
68
+ private tableName;
69
+ private initialized;
70
+ private initPromise;
71
+ constructor(options: PostgresKeyValueStoreOptions);
72
+ /**
73
+ * Initialize the store by creating the table if it doesn't exist.
74
+ * This is called automatically on first use.
75
+ */
76
+ private ensureInitialized;
77
+ /**
78
+ * Create the table if it doesn't exist.
79
+ */
80
+ private createTable;
81
+ /**
82
+ * Convert glob pattern to SQL LIKE pattern.
83
+ * Supports * wildcard (matches any characters).
84
+ */
85
+ private patternToLike;
86
+ get(key: string): Promise<string | null>;
87
+ set(key: string, value: string, options?: {
88
+ ttl?: number;
89
+ }): Promise<void>;
90
+ delete(key: string): Promise<boolean>;
91
+ exists(key: string): Promise<boolean>;
92
+ keys(pattern: string): Promise<string[]>;
93
+ /**
94
+ * Close the database connection pool.
95
+ * Call this when done with the store.
96
+ */
97
+ close(): Promise<void>;
98
+ }
99
+
100
+ /**
101
+ * Options for creating PostgreSQL persistence.
102
+ */
103
+ interface PostgresPersistenceOptions extends PostgresKeyValueStoreOptions {
104
+ /**
105
+ * Key prefix for state entries.
106
+ * @default 'workflow:state:'
107
+ */
108
+ prefix?: string;
109
+ }
110
+ /**
111
+ * Create a StatePersistence instance backed by PostgreSQL.
112
+ *
113
+ * The table is automatically created on first use.
114
+ *
115
+ * @param options - PostgreSQL connection and configuration options
116
+ * @returns StatePersistence instance ready to use with durable.run()
117
+ *
118
+ * @example
119
+ * ```typescript
120
+ * import { createPostgresPersistence } from 'awaitly-postgres';
121
+ * import { durable } from 'awaitly/durable';
122
+ *
123
+ * const store = await createPostgresPersistence({
124
+ * connectionString: process.env.DATABASE_URL,
125
+ * });
126
+ *
127
+ * const result = await durable.run(
128
+ * { fetchUser, createOrder },
129
+ * async (step, { fetchUser, createOrder }) => {
130
+ * const user = await step(() => fetchUser('123'), { key: 'fetch-user' });
131
+ * const order = await step(() => createOrder(user), { key: 'create-order' });
132
+ * return order;
133
+ * },
134
+ * {
135
+ * id: 'checkout-123',
136
+ * store,
137
+ * }
138
+ * );
139
+ * ```
140
+ *
141
+ * @example
142
+ * ```typescript
143
+ * // Using individual connection options
144
+ * const store = await createPostgresPersistence({
145
+ * host: 'localhost',
146
+ * port: 5432,
147
+ * database: 'myapp',
148
+ * user: 'postgres',
149
+ * password: 'password',
150
+ * tableName: 'custom_workflow_state',
151
+ * });
152
+ * ```
153
+ */
154
+ declare function createPostgresPersistence(options?: PostgresPersistenceOptions): Promise<StatePersistence & {
155
+ loadRaw(runId: string): Promise<awaitly_persistence.SerializedState | undefined>;
156
+ }>;
157
+
158
+ export { PostgresKeyValueStore, type PostgresKeyValueStoreOptions, type PostgresPersistenceOptions, createPostgresPersistence };
@@ -0,0 +1,158 @@
1
+ import * as awaitly_persistence from 'awaitly/persistence';
2
+ import { KeyValueStore, StatePersistence } from 'awaitly/persistence';
3
+ import { PoolConfig, Pool } from 'pg';
4
+
5
+ /**
6
+ * awaitly-postgres
7
+ *
8
+ * PostgreSQL KeyValueStore implementation for awaitly persistence.
9
+ */
10
+
11
+ /**
12
+ * Options for PostgreSQL KeyValueStore.
13
+ */
14
+ interface PostgresKeyValueStoreOptions {
15
+ /**
16
+ * PostgreSQL connection string.
17
+ * If provided, other connection options are ignored.
18
+ *
19
+ * @example 'postgresql://user:password@localhost:5432/dbname'
20
+ */
21
+ connectionString?: string;
22
+ /**
23
+ * Database host.
24
+ * @default 'localhost'
25
+ */
26
+ host?: string;
27
+ /**
28
+ * Database port.
29
+ * @default 5432
30
+ */
31
+ port?: number;
32
+ /**
33
+ * Database name.
34
+ */
35
+ database?: string;
36
+ /**
37
+ * Database user.
38
+ */
39
+ user?: string;
40
+ /**
41
+ * Database password.
42
+ */
43
+ password?: string;
44
+ /**
45
+ * Table name for storing key-value pairs.
46
+ * @default 'awaitly_workflow_state'
47
+ */
48
+ tableName?: string;
49
+ /**
50
+ * Additional pool configuration options.
51
+ * Ignored if `existingPool` is provided.
52
+ */
53
+ pool?: PoolConfig;
54
+ /**
55
+ * Existing PostgreSQL pool to use.
56
+ * If provided, connection options are ignored.
57
+ */
58
+ existingPool?: Pool;
59
+ }
60
+ /**
61
+ * PostgreSQL implementation of KeyValueStore.
62
+ *
63
+ * Automatically creates the required table on first use.
64
+ * Supports TTL via expires_at column.
65
+ */
66
+ declare class PostgresKeyValueStore implements KeyValueStore {
67
+ private pool;
68
+ private tableName;
69
+ private initialized;
70
+ private initPromise;
71
+ constructor(options: PostgresKeyValueStoreOptions);
72
+ /**
73
+ * Initialize the store by creating the table if it doesn't exist.
74
+ * This is called automatically on first use.
75
+ */
76
+ private ensureInitialized;
77
+ /**
78
+ * Create the table if it doesn't exist.
79
+ */
80
+ private createTable;
81
+ /**
82
+ * Convert glob pattern to SQL LIKE pattern.
83
+ * Supports * wildcard (matches any characters).
84
+ */
85
+ private patternToLike;
86
+ get(key: string): Promise<string | null>;
87
+ set(key: string, value: string, options?: {
88
+ ttl?: number;
89
+ }): Promise<void>;
90
+ delete(key: string): Promise<boolean>;
91
+ exists(key: string): Promise<boolean>;
92
+ keys(pattern: string): Promise<string[]>;
93
+ /**
94
+ * Close the database connection pool.
95
+ * Call this when done with the store.
96
+ */
97
+ close(): Promise<void>;
98
+ }
99
+
100
+ /**
101
+ * Options for creating PostgreSQL persistence.
102
+ */
103
+ interface PostgresPersistenceOptions extends PostgresKeyValueStoreOptions {
104
+ /**
105
+ * Key prefix for state entries.
106
+ * @default 'workflow:state:'
107
+ */
108
+ prefix?: string;
109
+ }
110
+ /**
111
+ * Create a StatePersistence instance backed by PostgreSQL.
112
+ *
113
+ * The table is automatically created on first use.
114
+ *
115
+ * @param options - PostgreSQL connection and configuration options
116
+ * @returns StatePersistence instance ready to use with durable.run()
117
+ *
118
+ * @example
119
+ * ```typescript
120
+ * import { createPostgresPersistence } from 'awaitly-postgres';
121
+ * import { durable } from 'awaitly/durable';
122
+ *
123
+ * const store = await createPostgresPersistence({
124
+ * connectionString: process.env.DATABASE_URL,
125
+ * });
126
+ *
127
+ * const result = await durable.run(
128
+ * { fetchUser, createOrder },
129
+ * async (step, { fetchUser, createOrder }) => {
130
+ * const user = await step(() => fetchUser('123'), { key: 'fetch-user' });
131
+ * const order = await step(() => createOrder(user), { key: 'create-order' });
132
+ * return order;
133
+ * },
134
+ * {
135
+ * id: 'checkout-123',
136
+ * store,
137
+ * }
138
+ * );
139
+ * ```
140
+ *
141
+ * @example
142
+ * ```typescript
143
+ * // Using individual connection options
144
+ * const store = await createPostgresPersistence({
145
+ * host: 'localhost',
146
+ * port: 5432,
147
+ * database: 'myapp',
148
+ * user: 'postgres',
149
+ * password: 'password',
150
+ * tableName: 'custom_workflow_state',
151
+ * });
152
+ * ```
153
+ */
154
+ declare function createPostgresPersistence(options?: PostgresPersistenceOptions): Promise<StatePersistence & {
155
+ loadRaw(runId: string): Promise<awaitly_persistence.SerializedState | undefined>;
156
+ }>;
157
+
158
+ export { PostgresKeyValueStore, type PostgresKeyValueStoreOptions, type PostgresPersistenceOptions, createPostgresPersistence };
package/dist/index.js ADDED
@@ -0,0 +1,35 @@
1
+ import{Pool as n}from"pg";var r=class{pool;tableName;initialized=!1;initPromise=null;constructor(e){e.existingPool?this.pool=e.existingPool:e.connectionString?this.pool=new n({connectionString:e.connectionString,...e.pool}):this.pool=new n({host:e.host??"localhost",port:e.port??5432,database:e.database,user:e.user,password:e.password,...e.pool}),this.tableName=e.tableName??"awaitly_workflow_state"}async ensureInitialized(){if(!this.initialized)return this.initPromise?this.initPromise:(this.initPromise=(async()=>{try{await this.createTable(),this.initialized=!0}catch(e){throw this.initPromise=null,e}})(),this.initPromise)}async createTable(){let e=`
2
+ CREATE TABLE IF NOT EXISTS ${this.tableName} (
3
+ key TEXT PRIMARY KEY,
4
+ value TEXT NOT NULL,
5
+ expires_at TIMESTAMP
6
+ );
7
+
8
+ CREATE INDEX IF NOT EXISTS idx_${this.tableName}_expires_at
9
+ ON ${this.tableName}(expires_at)
10
+ WHERE expires_at IS NOT NULL;
11
+ `;await this.pool.query(e)}patternToLike(e){return e.replace(/%/g,"\\%").replace(/_/g,"\\_").replace(/\*/g,"%")}async get(e){await this.ensureInitialized();let t=`
12
+ SELECT value
13
+ FROM ${this.tableName}
14
+ WHERE key = $1
15
+ AND (expires_at IS NULL OR expires_at > NOW())
16
+ `,i=await this.pool.query(t,[e]);return i.rows.length===0?null:i.rows[0].value}async set(e,t,i){await this.ensureInitialized();let o=i?.ttl?new Date(Date.now()+i.ttl*1e3):null,s=`
17
+ INSERT INTO ${this.tableName} (key, value, expires_at)
18
+ VALUES ($1, $2, $3)
19
+ ON CONFLICT (key)
20
+ DO UPDATE SET
21
+ value = EXCLUDED.value,
22
+ expires_at = EXCLUDED.expires_at
23
+ `;await this.pool.query(s,[e,t,o])}async delete(e){await this.ensureInitialized();let t=`DELETE FROM ${this.tableName} WHERE key = $1`;return((await this.pool.query(t,[e])).rowCount??0)>0}async exists(e){await this.ensureInitialized();let t=`
24
+ SELECT 1
25
+ FROM ${this.tableName}
26
+ WHERE key = $1
27
+ AND (expires_at IS NULL OR expires_at > NOW())
28
+ LIMIT 1
29
+ `;return(await this.pool.query(t,[e])).rows.length>0}async keys(e){await this.ensureInitialized();let t=this.patternToLike(e),i=`
30
+ SELECT key
31
+ FROM ${this.tableName}
32
+ WHERE key LIKE $1
33
+ AND (expires_at IS NULL OR expires_at > NOW())
34
+ `;return(await this.pool.query(i,[t])).rows.map(s=>s.key)}async close(){await this.pool.end()}};import{createStatePersistence as l}from"awaitly/persistence";async function g(a={}){let{prefix:e,...t}=a,i=new r(t);return l(i,e)}export{r as PostgresKeyValueStore,g as createPostgresPersistence};
35
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/postgres-store.ts","../src/index.ts"],"sourcesContent":["/**\n * awaitly-postgres\n *\n * PostgreSQL KeyValueStore implementation for awaitly persistence.\n */\n\nimport type { Pool, PoolConfig, QueryResult } from \"pg\";\nimport { Pool as PgPool } from \"pg\";\nimport type { KeyValueStore } from \"awaitly/persistence\";\n\n/**\n * Options for PostgreSQL KeyValueStore.\n */\nexport interface PostgresKeyValueStoreOptions {\n /**\n * PostgreSQL connection string.\n * If provided, other connection options are ignored.\n *\n * @example 'postgresql://user:password@localhost:5432/dbname'\n */\n connectionString?: string;\n\n /**\n * Database host.\n * @default 'localhost'\n */\n host?: string;\n\n /**\n * Database port.\n * @default 5432\n */\n port?: number;\n\n /**\n * Database name.\n */\n database?: string;\n\n /**\n * Database user.\n */\n user?: string;\n\n /**\n * Database password.\n */\n password?: string;\n\n /**\n * Table name for storing key-value pairs.\n * @default 'awaitly_workflow_state'\n */\n tableName?: string;\n\n /**\n * Additional pool configuration options.\n * Ignored if `existingPool` is provided.\n */\n pool?: PoolConfig;\n\n /**\n * Existing PostgreSQL pool to use.\n * If provided, connection options are ignored.\n */\n existingPool?: Pool;\n}\n\n/**\n * PostgreSQL implementation of KeyValueStore.\n *\n * Automatically creates the required table on first use.\n * Supports TTL via expires_at column.\n */\nexport class PostgresKeyValueStore implements KeyValueStore {\n private pool: Pool;\n private tableName: string;\n private initialized: boolean = false;\n private initPromise: Promise<void> | null = null;\n\n constructor(options: PostgresKeyValueStoreOptions) {\n if (options.existingPool) {\n // Use provided pool\n this.pool = options.existingPool;\n } else if (options.connectionString) {\n // Create pool from connection string\n this.pool = new PgPool({\n connectionString: options.connectionString,\n ...options.pool,\n });\n } else {\n // Create pool from individual options\n this.pool = new PgPool({\n host: options.host ?? \"localhost\",\n port: options.port ?? 5432,\n database: options.database,\n user: options.user,\n password: options.password,\n ...options.pool,\n });\n }\n\n this.tableName = options.tableName ?? \"awaitly_workflow_state\";\n }\n\n /**\n * Initialize the store by creating the table if it doesn't exist.\n * This is called automatically on first use.\n */\n private async ensureInitialized(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n if (this.initPromise) {\n return this.initPromise;\n }\n\n this.initPromise = (async () => {\n try {\n await this.createTable();\n this.initialized = true;\n } catch (error) {\n this.initPromise = null;\n throw error;\n }\n })();\n\n return this.initPromise;\n }\n\n /**\n * Create the table if it doesn't exist.\n */\n private async createTable(): Promise<void> {\n const query = `\n CREATE TABLE IF NOT EXISTS ${this.tableName} (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL,\n expires_at TIMESTAMP\n );\n\n CREATE INDEX IF NOT EXISTS idx_${this.tableName}_expires_at \n ON ${this.tableName}(expires_at) \n WHERE expires_at IS NOT NULL;\n `;\n\n await this.pool.query(query);\n }\n\n /**\n * Convert glob pattern to SQL LIKE pattern.\n * Supports * wildcard (matches any characters).\n */\n private patternToLike(pattern: string): string {\n // Escape SQL LIKE special characters and convert * to %\n return pattern.replace(/%/g, \"\\\\%\").replace(/_/g, \"\\\\_\").replace(/\\*/g, \"%\");\n }\n\n async get(key: string): Promise<string | null> {\n await this.ensureInitialized();\n\n const query = `\n SELECT value \n FROM ${this.tableName} \n WHERE key = $1 \n AND (expires_at IS NULL OR expires_at > NOW())\n `;\n\n const result: QueryResult<{ value: string }> = await this.pool.query(query, [key]);\n\n if (result.rows.length === 0) {\n return null;\n }\n\n return result.rows[0].value;\n }\n\n async set(key: string, value: string, options?: { ttl?: number }): Promise<void> {\n await this.ensureInitialized();\n\n const expiresAt = options?.ttl\n ? new Date(Date.now() + options.ttl * 1000)\n : null;\n\n const query = `\n INSERT INTO ${this.tableName} (key, value, expires_at)\n VALUES ($1, $2, $3)\n ON CONFLICT (key) \n DO UPDATE SET \n value = EXCLUDED.value,\n expires_at = EXCLUDED.expires_at\n `;\n\n await this.pool.query(query, [key, value, expiresAt]);\n }\n\n async delete(key: string): Promise<boolean> {\n await this.ensureInitialized();\n\n const query = `DELETE FROM ${this.tableName} WHERE key = $1`;\n const result = await this.pool.query(query, [key]);\n\n return (result.rowCount ?? 0) > 0;\n }\n\n async exists(key: string): Promise<boolean> {\n await this.ensureInitialized();\n\n const query = `\n SELECT 1 \n FROM ${this.tableName} \n WHERE key = $1 \n AND (expires_at IS NULL OR expires_at > NOW())\n LIMIT 1\n `;\n\n const result = await this.pool.query(query, [key]);\n return result.rows.length > 0;\n }\n\n async keys(pattern: string): Promise<string[]> {\n await this.ensureInitialized();\n\n // Convert glob pattern to SQL LIKE\n const likePattern = this.patternToLike(pattern);\n\n const query = `\n SELECT key \n FROM ${this.tableName} \n WHERE key LIKE $1 \n AND (expires_at IS NULL OR expires_at > NOW())\n `;\n\n const result: QueryResult<{ key: string }> = await this.pool.query(query, [likePattern]);\n\n return result.rows.map((row) => row.key);\n }\n\n /**\n * Close the database connection pool.\n * Call this when done with the store.\n */\n async close(): Promise<void> {\n await this.pool.end();\n }\n}\n","/**\n * awaitly-postgres\n *\n * PostgreSQL persistence adapter for awaitly workflows.\n * Provides ready-to-use StatePersistence backed by PostgreSQL.\n */\n\nimport { PostgresKeyValueStore, type PostgresKeyValueStoreOptions } from \"./postgres-store\";\nimport { createStatePersistence, type StatePersistence } from \"awaitly/persistence\";\n\n/**\n * Options for creating PostgreSQL persistence.\n */\nexport interface PostgresPersistenceOptions extends PostgresKeyValueStoreOptions {\n /**\n * Key prefix for state entries.\n * @default 'workflow:state:'\n */\n prefix?: string;\n}\n\n/**\n * Create a StatePersistence instance backed by PostgreSQL.\n *\n * The table is automatically created on first use.\n *\n * @param options - PostgreSQL connection and configuration options\n * @returns StatePersistence instance ready to use with durable.run()\n *\n * @example\n * ```typescript\n * import { createPostgresPersistence } from 'awaitly-postgres';\n * import { durable } from 'awaitly/durable';\n *\n * const store = await createPostgresPersistence({\n * connectionString: process.env.DATABASE_URL,\n * });\n *\n * const result = await durable.run(\n * { fetchUser, createOrder },\n * async (step, { fetchUser, createOrder }) => {\n * const user = await step(() => fetchUser('123'), { key: 'fetch-user' });\n * const order = await step(() => createOrder(user), { key: 'create-order' });\n * return order;\n * },\n * {\n * id: 'checkout-123',\n * store,\n * }\n * );\n * ```\n *\n * @example\n * ```typescript\n * // Using individual connection options\n * const store = await createPostgresPersistence({\n * host: 'localhost',\n * port: 5432,\n * database: 'myapp',\n * user: 'postgres',\n * password: 'password',\n * tableName: 'custom_workflow_state',\n * });\n * ```\n */\nexport async function createPostgresPersistence(\n options: PostgresPersistenceOptions = {}\n): Promise<StatePersistence & { loadRaw(runId: string): Promise<import(\"awaitly/persistence\").SerializedState | undefined> }> {\n const { prefix, ...storeOptions } = options;\n\n const store = new PostgresKeyValueStore(storeOptions);\n return createStatePersistence(store, prefix);\n}\n\n/**\n * PostgreSQL KeyValueStore implementation.\n * Use this directly if you need more control over the store.\n *\n * @example\n * ```typescript\n * import { PostgresKeyValueStore } from 'awaitly-postgres';\n * import { createStatePersistence } from 'awaitly/persistence';\n *\n * const store = new PostgresKeyValueStore({\n * connectionString: process.env.DATABASE_URL,\n * });\n *\n * const persistence = createStatePersistence(store, 'custom:prefix:');\n * ```\n */\nexport { PostgresKeyValueStore, type PostgresKeyValueStoreOptions };\n"],"mappings":"AAOA,OAAS,QAAQA,MAAc,KAmExB,IAAMC,EAAN,KAAqD,CAClD,KACA,UACA,YAAuB,GACvB,YAAoC,KAE5C,YAAYC,EAAuC,CAC7CA,EAAQ,aAEV,KAAK,KAAOA,EAAQ,aACXA,EAAQ,iBAEjB,KAAK,KAAO,IAAIF,EAAO,CACrB,iBAAkBE,EAAQ,iBAC1B,GAAGA,EAAQ,IACb,CAAC,EAGD,KAAK,KAAO,IAAIF,EAAO,CACrB,KAAME,EAAQ,MAAQ,YACtB,KAAMA,EAAQ,MAAQ,KACtB,SAAUA,EAAQ,SAClB,KAAMA,EAAQ,KACd,SAAUA,EAAQ,SAClB,GAAGA,EAAQ,IACb,CAAC,EAGH,KAAK,UAAYA,EAAQ,WAAa,wBACxC,CAMA,MAAc,mBAAmC,CAC/C,GAAI,MAAK,YAIT,OAAI,KAAK,YACA,KAAK,aAGd,KAAK,aAAe,SAAY,CAC9B,GAAI,CACF,MAAM,KAAK,YAAY,EACvB,KAAK,YAAc,EACrB,OAASC,EAAO,CACd,WAAK,YAAc,KACbA,CACR,CACF,GAAG,EAEI,KAAK,YACd,CAKA,MAAc,aAA6B,CACzC,IAAMC,EAAQ;AAAA,mCACiB,KAAK,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uCAMV,KAAK,SAAS;AAAA,WAC1C,KAAK,SAAS;AAAA;AAAA,MAIrB,MAAM,KAAK,KAAK,MAAMA,CAAK,CAC7B,CAMQ,cAAcC,EAAyB,CAE7C,OAAOA,EAAQ,QAAQ,KAAM,KAAK,EAAE,QAAQ,KAAM,KAAK,EAAE,QAAQ,MAAO,GAAG,CAC7E,CAEA,MAAM,IAAIC,EAAqC,CAC7C,MAAM,KAAK,kBAAkB,EAE7B,IAAMF,EAAQ;AAAA;AAAA,aAEL,KAAK,SAAS;AAAA;AAAA;AAAA,MAKjBG,EAAyC,MAAM,KAAK,KAAK,MAAMH,EAAO,CAACE,CAAG,CAAC,EAEjF,OAAIC,EAAO,KAAK,SAAW,EAClB,KAGFA,EAAO,KAAK,CAAC,EAAE,KACxB,CAEA,MAAM,IAAID,EAAaE,EAAeN,EAA2C,CAC/E,MAAM,KAAK,kBAAkB,EAE7B,IAAMO,EAAYP,GAAS,IACvB,IAAI,KAAK,KAAK,IAAI,EAAIA,EAAQ,IAAM,GAAI,EACxC,KAEEE,EAAQ;AAAA,oBACE,KAAK,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQ9B,MAAM,KAAK,KAAK,MAAMA,EAAO,CAACE,EAAKE,EAAOC,CAAS,CAAC,CACtD,CAEA,MAAM,OAAOH,EAA+B,CAC1C,MAAM,KAAK,kBAAkB,EAE7B,IAAMF,EAAQ,eAAe,KAAK,SAAS,kBAG3C,QAFe,MAAM,KAAK,KAAK,MAAMA,EAAO,CAACE,CAAG,CAAC,GAElC,UAAY,GAAK,CAClC,CAEA,MAAM,OAAOA,EAA+B,CAC1C,MAAM,KAAK,kBAAkB,EAE7B,IAAMF,EAAQ;AAAA;AAAA,aAEL,KAAK,SAAS;AAAA;AAAA;AAAA;AAAA,MAOvB,OADe,MAAM,KAAK,KAAK,MAAMA,EAAO,CAACE,CAAG,CAAC,GACnC,KAAK,OAAS,CAC9B,CAEA,MAAM,KAAKD,EAAoC,CAC7C,MAAM,KAAK,kBAAkB,EAG7B,IAAMK,EAAc,KAAK,cAAcL,CAAO,EAExCD,EAAQ;AAAA;AAAA,aAEL,KAAK,SAAS;AAAA;AAAA;AAAA,MAOvB,OAF6C,MAAM,KAAK,KAAK,MAAMA,EAAO,CAACM,CAAW,CAAC,GAEzE,KAAK,IAAKC,GAAQA,EAAI,GAAG,CACzC,CAMA,MAAM,OAAuB,CAC3B,MAAM,KAAK,KAAK,IAAI,CACtB,CACF,EC9OA,OAAS,0BAAAC,MAAqD,sBAyD9D,eAAsBC,EACpBC,EAAsC,CAAC,EACqF,CAC5H,GAAM,CAAE,OAAAC,EAAQ,GAAGC,CAAa,EAAIF,EAE9BG,EAAQ,IAAIC,EAAsBF,CAAY,EACpD,OAAOJ,EAAuBK,EAAOF,CAAM,CAC7C","names":["PgPool","PostgresKeyValueStore","options","error","query","pattern","key","result","value","expiresAt","likePattern","row","createStatePersistence","createPostgresPersistence","options","prefix","storeOptions","store","PostgresKeyValueStore"]}
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "awaitly-postgres",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "PostgreSQL persistence adapter for awaitly workflows",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "sideEffects": false,
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js",
14
+ "require": "./dist/index.cjs"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "README.md"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsup",
23
+ "type-check": "tsc --noEmit",
24
+ "test": "vitest run",
25
+ "test:watch": "vitest watch",
26
+ "lint": "eslint .",
27
+ "clean": "rm -rf dist",
28
+ "quality": "pnpm type-check && pnpm test && pnpm lint"
29
+ },
30
+ "keywords": [
31
+ "awaitly",
32
+ "workflow",
33
+ "persistence",
34
+ "postgres",
35
+ "postgresql",
36
+ "database",
37
+ "durable-execution"
38
+ ],
39
+ "author": "Jag Reehal <jag@jagreehal.com>",
40
+ "homepage": "https://github.com/jagreehal/awaitly#readme",
41
+ "bugs": {
42
+ "url": "https://github.com/jagreehal/awaitly/issues"
43
+ },
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "git+https://github.com/jagreehal/awaitly.git"
47
+ },
48
+ "license": "MIT",
49
+ "peerDependencies": {
50
+ "awaitly": "workspace:^"
51
+ },
52
+ "dependencies": {
53
+ "pg": "^8.13.1"
54
+ },
55
+ "devDependencies": {
56
+ "@total-typescript/ts-reset": "^0.6.1",
57
+ "@total-typescript/tsconfig": "^1.0.4",
58
+ "@types/node": "^25.0.10",
59
+ "@types/pg": "^8.11.10",
60
+ "awaitly": "workspace:^",
61
+ "tsup": "^8.5.1",
62
+ "typescript": "^5.9.3",
63
+ "vitest": "^4.0.18"
64
+ },
65
+ "publishConfig": {
66
+ "access": "public",
67
+ "registry": "https://registry.npmjs.org/"
68
+ },
69
+ "engines": {
70
+ "node": ">=22"
71
+ }
72
+ }