@periodic/vanadium 1.0.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.
Files changed (136) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/LICENSE +21 -0
  3. package/README.md +846 -0
  4. package/dist/cjs/adapters/memory/index.js +134 -0
  5. package/dist/cjs/adapters/memory/index.js.map +1 -0
  6. package/dist/cjs/adapters/mongodb/index.js +189 -0
  7. package/dist/cjs/adapters/mongodb/index.js.map +1 -0
  8. package/dist/cjs/adapters/mongoose/index.js +199 -0
  9. package/dist/cjs/adapters/mongoose/index.js.map +1 -0
  10. package/dist/cjs/adapters/postgres/index.js +202 -0
  11. package/dist/cjs/adapters/postgres/index.js.map +1 -0
  12. package/dist/cjs/adapters/prisma/index.js +176 -0
  13. package/dist/cjs/adapters/prisma/index.js.map +1 -0
  14. package/dist/cjs/adapters/redis/index.js +178 -0
  15. package/dist/cjs/adapters/redis/index.js.map +1 -0
  16. package/dist/cjs/cleanup/engine.js +100 -0
  17. package/dist/cjs/cleanup/engine.js.map +1 -0
  18. package/dist/cjs/core/concurrencyGuard.js +50 -0
  19. package/dist/cjs/core/concurrencyGuard.js.map +1 -0
  20. package/dist/cjs/core/metrics.js +39 -0
  21. package/dist/cjs/core/metrics.js.map +1 -0
  22. package/dist/cjs/core/stateMachine.js +46 -0
  23. package/dist/cjs/core/stateMachine.js.map +1 -0
  24. package/dist/cjs/errors/index.js +127 -0
  25. package/dist/cjs/errors/index.js.map +1 -0
  26. package/dist/cjs/http/express.js +84 -0
  27. package/dist/cjs/http/express.js.map +1 -0
  28. package/dist/cjs/http/fastify.js +70 -0
  29. package/dist/cjs/http/fastify.js.map +1 -0
  30. package/dist/cjs/idempotency/engine.js +266 -0
  31. package/dist/cjs/idempotency/engine.js.map +1 -0
  32. package/dist/cjs/index.js +19 -0
  33. package/dist/cjs/index.js.map +1 -0
  34. package/dist/cjs/lock/engine.js +187 -0
  35. package/dist/cjs/lock/engine.js.map +1 -0
  36. package/dist/cjs/observability/metrics.js +92 -0
  37. package/dist/cjs/observability/metrics.js.map +1 -0
  38. package/dist/cjs/resilience/circuitBreaker.js +129 -0
  39. package/dist/cjs/resilience/circuitBreaker.js.map +1 -0
  40. package/dist/cjs/types/index.js +13 -0
  41. package/dist/cjs/types/index.js.map +1 -0
  42. package/dist/cjs/utils/crypto.js +64 -0
  43. package/dist/cjs/utils/crypto.js.map +1 -0
  44. package/dist/cjs/utils/keys.js +40 -0
  45. package/dist/cjs/utils/keys.js.map +1 -0
  46. package/dist/cjs/utils/sleep.js +25 -0
  47. package/dist/cjs/utils/sleep.js.map +1 -0
  48. package/dist/esm/adapters/memory/index.js +129 -0
  49. package/dist/esm/adapters/memory/index.js.map +1 -0
  50. package/dist/esm/adapters/mongodb/index.js +184 -0
  51. package/dist/esm/adapters/mongodb/index.js.map +1 -0
  52. package/dist/esm/adapters/mongoose/index.js +193 -0
  53. package/dist/esm/adapters/mongoose/index.js.map +1 -0
  54. package/dist/esm/adapters/postgres/index.js +197 -0
  55. package/dist/esm/adapters/postgres/index.js.map +1 -0
  56. package/dist/esm/adapters/prisma/index.js +171 -0
  57. package/dist/esm/adapters/prisma/index.js.map +1 -0
  58. package/dist/esm/adapters/redis/index.js +173 -0
  59. package/dist/esm/adapters/redis/index.js.map +1 -0
  60. package/dist/esm/cleanup/engine.js +95 -0
  61. package/dist/esm/cleanup/engine.js.map +1 -0
  62. package/dist/esm/core/concurrencyGuard.js +46 -0
  63. package/dist/esm/core/concurrencyGuard.js.map +1 -0
  64. package/dist/esm/core/metrics.js +35 -0
  65. package/dist/esm/core/metrics.js.map +1 -0
  66. package/dist/esm/core/stateMachine.js +40 -0
  67. package/dist/esm/core/stateMachine.js.map +1 -0
  68. package/dist/esm/errors/index.js +114 -0
  69. package/dist/esm/errors/index.js.map +1 -0
  70. package/dist/esm/http/express.js +81 -0
  71. package/dist/esm/http/express.js.map +1 -0
  72. package/dist/esm/http/fastify.js +67 -0
  73. package/dist/esm/http/fastify.js.map +1 -0
  74. package/dist/esm/idempotency/engine.js +261 -0
  75. package/dist/esm/idempotency/engine.js.map +1 -0
  76. package/dist/esm/index.js +9 -0
  77. package/dist/esm/index.js.map +1 -0
  78. package/dist/esm/lock/engine.js +182 -0
  79. package/dist/esm/lock/engine.js.map +1 -0
  80. package/dist/esm/observability/metrics.js +89 -0
  81. package/dist/esm/observability/metrics.js.map +1 -0
  82. package/dist/esm/resilience/circuitBreaker.js +124 -0
  83. package/dist/esm/resilience/circuitBreaker.js.map +1 -0
  84. package/dist/esm/types/index.js +10 -0
  85. package/dist/esm/types/index.js.map +1 -0
  86. package/dist/esm/utils/crypto.js +58 -0
  87. package/dist/esm/utils/crypto.js.map +1 -0
  88. package/dist/esm/utils/keys.js +35 -0
  89. package/dist/esm/utils/keys.js.map +1 -0
  90. package/dist/esm/utils/sleep.js +20 -0
  91. package/dist/esm/utils/sleep.js.map +1 -0
  92. package/dist/types/adapters/memory/index.d.ts +49 -0
  93. package/dist/types/adapters/memory/index.d.ts.map +1 -0
  94. package/dist/types/adapters/mongodb/index.d.ts +97 -0
  95. package/dist/types/adapters/mongodb/index.d.ts.map +1 -0
  96. package/dist/types/adapters/mongoose/index.d.ts +107 -0
  97. package/dist/types/adapters/mongoose/index.d.ts.map +1 -0
  98. package/dist/types/adapters/postgres/index.d.ts +85 -0
  99. package/dist/types/adapters/postgres/index.d.ts.map +1 -0
  100. package/dist/types/adapters/prisma/index.d.ts +73 -0
  101. package/dist/types/adapters/prisma/index.d.ts.map +1 -0
  102. package/dist/types/adapters/redis/index.d.ts +77 -0
  103. package/dist/types/adapters/redis/index.d.ts.map +1 -0
  104. package/dist/types/cleanup/engine.d.ts +41 -0
  105. package/dist/types/cleanup/engine.d.ts.map +1 -0
  106. package/dist/types/core/concurrencyGuard.d.ts +28 -0
  107. package/dist/types/core/concurrencyGuard.d.ts.map +1 -0
  108. package/dist/types/core/metrics.d.ts +13 -0
  109. package/dist/types/core/metrics.d.ts.map +1 -0
  110. package/dist/types/core/stateMachine.d.ts +20 -0
  111. package/dist/types/core/stateMachine.d.ts.map +1 -0
  112. package/dist/types/errors/index.d.ts +32 -0
  113. package/dist/types/errors/index.d.ts.map +1 -0
  114. package/dist/types/http/express.d.ts +50 -0
  115. package/dist/types/http/express.d.ts.map +1 -0
  116. package/dist/types/http/fastify.d.ts +48 -0
  117. package/dist/types/http/fastify.d.ts.map +1 -0
  118. package/dist/types/idempotency/engine.d.ts +24 -0
  119. package/dist/types/idempotency/engine.d.ts.map +1 -0
  120. package/dist/types/index.d.ts +8 -0
  121. package/dist/types/index.d.ts.map +1 -0
  122. package/dist/types/lock/engine.d.ts +28 -0
  123. package/dist/types/lock/engine.d.ts.map +1 -0
  124. package/dist/types/observability/metrics.d.ts +45 -0
  125. package/dist/types/observability/metrics.d.ts.map +1 -0
  126. package/dist/types/resilience/circuitBreaker.d.ts +48 -0
  127. package/dist/types/resilience/circuitBreaker.d.ts.map +1 -0
  128. package/dist/types/types/index.d.ts +170 -0
  129. package/dist/types/types/index.d.ts.map +1 -0
  130. package/dist/types/utils/crypto.d.ts +20 -0
  131. package/dist/types/utils/crypto.d.ts.map +1 -0
  132. package/dist/types/utils/keys.d.ts +15 -0
  133. package/dist/types/utils/keys.d.ts.map +1 -0
  134. package/dist/types/utils/sleep.d.ts +13 -0
  135. package/dist/types/utils/sleep.d.ts.map +1 -0
  136. package/package.json +140 -0
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Mongoose Storage Adapter Wrapper for @periodic/vanadium
3
+ *
4
+ * Peer dependency: "mongoose" >= 7.0.0
5
+ * Import: import { createMongooseAdapter } from '@periodic/vanadium/adapters/mongoose'
6
+ *
7
+ * This is a WRAPPER that preserves identical semantics to the MongoDB native adapter.
8
+ * Mongoose is purely an ORM layer — it does NOT change idempotency behavior.
9
+ *
10
+ * Required Prisma schema:
11
+ * ```prisma
12
+ * model vanadiumRecord {
13
+ * id String @id @map("_id")
14
+ * status String
15
+ * result Json?
16
+ * payloadHash String?
17
+ * ownerToken String?
18
+ * attempts Int @default(0)
19
+ * createdAt BigInt
20
+ * updatedAt BigInt
21
+ * expiresAt BigInt?
22
+ * }
23
+ * ```
24
+ *
25
+ * Required Mongoose schema (use createVanadiumSchema() helper):
26
+ * ```ts
27
+ * import { createVanadiumSchema } from '@periodic/vanadium/adapters/mongoose';
28
+ * const VanadiumRecord = mongoose.model('VanadiumRecord', createVanadiumSchema());
29
+ * ```
30
+ */
31
+ import { createStorageError, createConfigurationError } from '../../errors/index.js';
32
+ /* eslint-enable @typescript-eslint/no-explicit-any */
33
+ const MONGOOSE_DUPLICATE_KEY_CODE = 11000;
34
+ // ─── Mongoose Adapter ─────────────────────────────────────────────────────────
35
+ export class MongooseAdapter {
36
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
37
+ constructor(options) {
38
+ this.name = 'mongoose';
39
+ if (!options.model) {
40
+ throw createConfigurationError('', 'mongoose', 'Mongoose adapter requires a model.');
41
+ }
42
+ this.model = options.model;
43
+ this.useTransactions = options.useTransactions ?? true;
44
+ this.clock = options.clock ?? Date.now;
45
+ }
46
+ // ── Storage Interface ─────────────────────────────────────────────────────
47
+ async get(key) {
48
+ try {
49
+ const doc = await this.model.findOne({ _id: key });
50
+ if (!doc)
51
+ return null;
52
+ return this._docToRecord(doc);
53
+ }
54
+ catch (err) {
55
+ throw createStorageError(key, this.name, err, this.clock);
56
+ }
57
+ }
58
+ async set(key, value, ttlMs) {
59
+ const now = this.clock();
60
+ const expiresAt = ttlMs !== undefined ? now + ttlMs : value.expiresAt;
61
+ const docData = {
62
+ _id: key,
63
+ status: value.status,
64
+ result: value.result,
65
+ payloadHash: value.payloadHash,
66
+ ownerToken: value.ownerToken,
67
+ attempts: value.attempts,
68
+ createdAt: value.createdAt,
69
+ updatedAt: value.updatedAt,
70
+ expiresAt,
71
+ };
72
+ try {
73
+ await this.model.create(docData);
74
+ }
75
+ catch (err) {
76
+ const code = err.code;
77
+ if (code !== MONGOOSE_DUPLICATE_KEY_CODE) {
78
+ throw createStorageError(key, this.name, err, this.clock);
79
+ }
80
+ // Key exists — update
81
+ try {
82
+ await this.model.findOneAndUpdate({ _id: key }, {
83
+ $set: {
84
+ status: value.status,
85
+ result: value.result,
86
+ payloadHash: value.payloadHash,
87
+ ownerToken: value.ownerToken,
88
+ attempts: value.attempts,
89
+ updatedAt: value.updatedAt,
90
+ expiresAt,
91
+ },
92
+ }, { new: true });
93
+ }
94
+ catch (updateErr) {
95
+ throw createStorageError(key, this.name, updateErr, this.clock);
96
+ }
97
+ }
98
+ }
99
+ async delete(key) {
100
+ try {
101
+ await this.model.deleteOne({ _id: key });
102
+ }
103
+ catch (err) {
104
+ throw createStorageError(key, this.name, err, this.clock);
105
+ }
106
+ }
107
+ async compareAndSet(key, expectedOwnerToken, newValue, ttlMs) {
108
+ const now = this.clock();
109
+ const expiresAt = ttlMs !== undefined ? now + ttlMs : newValue.expiresAt;
110
+ try {
111
+ const result = await this.model.findOneAndUpdate({ _id: key, ownerToken: expectedOwnerToken }, {
112
+ $set: {
113
+ status: newValue.status,
114
+ result: newValue.result,
115
+ payloadHash: newValue.payloadHash,
116
+ ownerToken: newValue.ownerToken,
117
+ attempts: newValue.attempts,
118
+ updatedAt: newValue.updatedAt,
119
+ expiresAt,
120
+ },
121
+ }, { new: true });
122
+ return result !== null;
123
+ }
124
+ catch (err) {
125
+ throw createStorageError(key, this.name, err, this.clock);
126
+ }
127
+ }
128
+ // ── Capabilities ──────────────────────────────────────────────────────────
129
+ capabilities() {
130
+ return {
131
+ transactions: this.useTransactions,
132
+ cas: true,
133
+ ttl: true,
134
+ advisoryLocks: false,
135
+ };
136
+ }
137
+ // ── Private ───────────────────────────────────────────────────────────────
138
+ _docToRecord(doc) {
139
+ return {
140
+ key: doc._id,
141
+ status: doc.status,
142
+ result: doc.result,
143
+ payloadHash: doc.payloadHash,
144
+ ownerToken: doc.ownerToken,
145
+ attempts: doc.attempts,
146
+ createdAt: doc.createdAt,
147
+ updatedAt: doc.updatedAt,
148
+ expiresAt: doc.expiresAt,
149
+ };
150
+ }
151
+ }
152
+ // ─── Schema Builder ───────────────────────────────────────────────────────────
153
+ /**
154
+ * Build the required Mongoose schema for Vanadium records.
155
+ * Pass the Mongoose Schema constructor from your mongoose import.
156
+ */
157
+ export function createVanadiumSchema(Schema) {
158
+ return new Schema({
159
+ _id: { type: String, required: true },
160
+ status: {
161
+ type: String,
162
+ enum: ['IN_PROGRESS', 'COMPLETED', 'FAILED'],
163
+ required: true,
164
+ },
165
+ result: { type: Schema.Types.Mixed },
166
+ payloadHash: { type: String },
167
+ ownerToken: { type: String },
168
+ attempts: { type: Number, default: 0 },
169
+ createdAt: { type: Number, required: true },
170
+ updatedAt: { type: Number, required: true },
171
+ expiresAt: { type: Number },
172
+ }, {
173
+ versionKey: false,
174
+ strict: true,
175
+ });
176
+ }
177
+ // ─── Factory ──────────────────────────────────────────────────────────────────
178
+ /**
179
+ * Create a Mongoose storage adapter.
180
+ *
181
+ * @example
182
+ * ```ts
183
+ * import mongoose from 'mongoose';
184
+ * import { createMongooseAdapter, createVanadiumSchema } from '@periodic/vanadium/adapters/mongoose';
185
+ *
186
+ * const VanadiumRecord = mongoose.model('VanadiumRecord', createVanadiumSchema(mongoose.Schema));
187
+ * const adapter = createMongooseAdapter({ model: VanadiumRecord });
188
+ * ```
189
+ */
190
+ export function createMongooseAdapter(options) {
191
+ return new MongooseAdapter(options);
192
+ }
193
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapters/mongoose/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,197 @@
1
+ /**
2
+ * PostgreSQL Storage Adapter for @periodic/vanadium
3
+ *
4
+ * Peer dependency: "pg" >= 8.0.0
5
+ * Import: import { createPostgresAdapter } from '@periodic/vanadium/adapters/postgres'
6
+ *
7
+ * The caller MUST provide an already-created Pool or Client instance.
8
+ * This adapter never creates or closes connections.
9
+ *
10
+ * Required schema:
11
+ * ```sql
12
+ * CREATE TABLE public.vanadium_records (
13
+ * key TEXT PRIMARY KEY,
14
+ * status TEXT NOT NULL CHECK (status IN ('IN_PROGRESS','COMPLETED','FAILED')),
15
+ * result JSONB,
16
+ * payload_hash TEXT,
17
+ * owner_token TEXT,
18
+ * attempts INTEGER NOT NULL DEFAULT 0,
19
+ * created_at BIGINT NOT NULL,
20
+ * updated_at BIGINT NOT NULL,
21
+ * expires_at BIGINT
22
+ * );
23
+ * CREATE INDEX idx_vanadium_expires_at ON public.vanadium_records (expires_at);
24
+ * CREATE INDEX idx_vanadium_status_expires ON public.vanadium_records (status, expires_at);
25
+ * ```
26
+ */
27
+ import { createStorageError, createConfigurationError } from '../../errors/index.js';
28
+ // ─── Postgres Adapter ─────────────────────────────────────────────────────────
29
+ export class PostgresAdapter {
30
+ constructor(options) {
31
+ this.name = 'postgres';
32
+ if (!options.client) {
33
+ throw createConfigurationError('', 'postgres', 'Postgres adapter requires a pg Pool or Client.');
34
+ }
35
+ this.client = options.client;
36
+ const schema = options.schemaName ?? 'public';
37
+ const table = options.tableName ?? 'vanadium_records';
38
+ this.table = `${schema}.${table}`;
39
+ this.useAdvisoryLocks = options.useAdvisoryLocks ?? false;
40
+ this.clock = options.clock ?? Date.now;
41
+ }
42
+ // ── Storage Interface ─────────────────────────────────────────────────────
43
+ async get(key) {
44
+ const sql = `SELECT * FROM ${this.table} WHERE key = $1 LIMIT 1`;
45
+ try {
46
+ const res = await this.client.query(sql, [key]);
47
+ if (!res.rows.length)
48
+ return null;
49
+ return this._rowToRecord(res.rows[0]);
50
+ }
51
+ catch (err) {
52
+ throw createStorageError(key, this.name, err, this.clock);
53
+ }
54
+ }
55
+ async set(key, value, ttlMs) {
56
+ const now = this.clock();
57
+ const expiresAt = ttlMs !== undefined ? now + ttlMs : (value.expiresAt ?? null);
58
+ const resultJson = value.result !== undefined ? JSON.stringify(value.result) : null;
59
+ const sql = `
60
+ INSERT INTO ${this.table}
61
+ (key, status, result, payload_hash, owner_token, attempts, created_at, updated_at, expires_at)
62
+ VALUES
63
+ ($1, $2, $3::jsonb, $4, $5, $6, $7, $8, $9)
64
+ ON CONFLICT (key) DO UPDATE
65
+ SET status = EXCLUDED.status,
66
+ result = EXCLUDED.result,
67
+ payload_hash = EXCLUDED.payload_hash,
68
+ owner_token = EXCLUDED.owner_token,
69
+ attempts = EXCLUDED.attempts,
70
+ updated_at = EXCLUDED.updated_at,
71
+ expires_at = EXCLUDED.expires_at
72
+ `;
73
+ try {
74
+ await this.client.query(sql, [
75
+ key,
76
+ value.status,
77
+ resultJson,
78
+ value.payloadHash ?? null,
79
+ value.ownerToken ?? null,
80
+ value.attempts,
81
+ value.createdAt,
82
+ value.updatedAt,
83
+ expiresAt,
84
+ ]);
85
+ }
86
+ catch (err) {
87
+ throw createStorageError(key, this.name, err, this.clock);
88
+ }
89
+ }
90
+ async delete(key) {
91
+ const sql = `DELETE FROM ${this.table} WHERE key = $1`;
92
+ try {
93
+ await this.client.query(sql, [key]);
94
+ }
95
+ catch (err) {
96
+ throw createStorageError(key, this.name, err, this.clock);
97
+ }
98
+ }
99
+ async compareAndSet(key, expectedOwnerToken, newValue, ttlMs) {
100
+ const now = this.clock();
101
+ const expiresAt = ttlMs !== undefined ? now + ttlMs : (newValue.expiresAt ?? null);
102
+ const resultJson = newValue.result !== undefined ? JSON.stringify(newValue.result) : null;
103
+ const sql = `
104
+ UPDATE ${this.table}
105
+ SET status = $1,
106
+ result = $2::jsonb,
107
+ payload_hash = $3,
108
+ owner_token = $4,
109
+ attempts = $5,
110
+ updated_at = $6,
111
+ expires_at = $7
112
+ WHERE key = $8
113
+ AND owner_token = $9
114
+ `;
115
+ try {
116
+ const res = await this.client.query(sql, [
117
+ newValue.status,
118
+ resultJson,
119
+ newValue.payloadHash ?? null,
120
+ newValue.ownerToken ?? null,
121
+ newValue.attempts,
122
+ newValue.updatedAt,
123
+ expiresAt,
124
+ key,
125
+ expectedOwnerToken,
126
+ ]);
127
+ return (res.rowCount ?? 0) > 0;
128
+ }
129
+ catch (err) {
130
+ throw createStorageError(key, this.name, err, this.clock);
131
+ }
132
+ }
133
+ // ── Advisory Locks ────────────────────────────────────────────────────────
134
+ async tryAdvisoryLock(key) {
135
+ if (!this.useAdvisoryLocks)
136
+ return false;
137
+ const sql = `SELECT pg_try_advisory_lock(hashtext($1)) AS acquired`;
138
+ try {
139
+ const res = await this.client.query(sql, [key]);
140
+ return res.rows[0].acquired === true;
141
+ }
142
+ catch (err) {
143
+ throw createStorageError(key, this.name, err, this.clock);
144
+ }
145
+ }
146
+ async releaseAdvisoryLock(key) {
147
+ if (!this.useAdvisoryLocks)
148
+ return;
149
+ const sql = `SELECT pg_advisory_unlock(hashtext($1))`;
150
+ try {
151
+ await this.client.query(sql, [key]);
152
+ }
153
+ catch (err) {
154
+ throw createStorageError(key, this.name, err, this.clock);
155
+ }
156
+ }
157
+ // ── Capabilities ──────────────────────────────────────────────────────────
158
+ capabilities() {
159
+ return {
160
+ transactions: true,
161
+ cas: true,
162
+ ttl: false, // TTL enforced at application layer
163
+ advisoryLocks: this.useAdvisoryLocks,
164
+ };
165
+ }
166
+ // ── Private ───────────────────────────────────────────────────────────────
167
+ _rowToRecord(row) {
168
+ return {
169
+ key: row.key,
170
+ status: row.status,
171
+ result: row.result,
172
+ payloadHash: row.payload_hash ?? undefined,
173
+ ownerToken: row.owner_token ?? undefined,
174
+ attempts: row.attempts,
175
+ createdAt: Number(row.created_at),
176
+ updatedAt: Number(row.updated_at),
177
+ expiresAt: row.expires_at !== null ? Number(row.expires_at) : undefined,
178
+ };
179
+ }
180
+ }
181
+ // ─── Factory ──────────────────────────────────────────────────────────────────
182
+ /**
183
+ * Create a PostgreSQL storage adapter.
184
+ *
185
+ * @example
186
+ * ```ts
187
+ * import { Pool } from 'pg';
188
+ * import { createPostgresAdapter } from '@periodic/vanadium/adapters/postgres';
189
+ *
190
+ * const pool = new Pool({ connectionString: process.env.DATABASE_URL });
191
+ * const adapter = createPostgresAdapter({ client: pool });
192
+ * ```
193
+ */
194
+ export function createPostgresAdapter(options) {
195
+ return new PostgresAdapter(options);
196
+ }
197
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapters/postgres/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Prisma Storage Adapter for @periodic/vanadium
3
+ *
4
+ * Peer dependency: "@prisma/client" >= 5.0.0
5
+ * Import: import { createPrismaAdapter } from '@periodic/vanadium/adapters/prisma'
6
+ *
7
+ * Required Prisma schema model:
8
+ * ```prisma
9
+ * model VanadiumRecord {
10
+ * key String @id
11
+ * status String
12
+ * result Json?
13
+ * payloadHash String?
14
+ * ownerToken String?
15
+ * attempts Int @default(0)
16
+ * createdAt BigInt
17
+ * updatedAt BigInt
18
+ * expiresAt BigInt?
19
+ *
20
+ * @@map("vanadium_records")
21
+ * }
22
+ * ```
23
+ */
24
+ import { createStorageError, createConfigurationError } from '../../errors/index.js';
25
+ // ─── Prisma Adapter ───────────────────────────────────────────────────────────
26
+ export class PrismaAdapter {
27
+ constructor(options) {
28
+ this.name = 'prisma';
29
+ if (!options.prisma) {
30
+ throw createConfigurationError('', 'prisma', 'Prisma adapter requires a PrismaClient instance.');
31
+ }
32
+ this.prisma = options.prisma;
33
+ this.modelName = options.modelName ?? 'vanadiumRecord';
34
+ this.useTransactions = options.useInteractiveTransactions ?? true;
35
+ this.clock = options.clock ?? Date.now;
36
+ }
37
+ get model() {
38
+ const m = this.prisma[this.modelName];
39
+ if (!m) {
40
+ throw createConfigurationError('', 'prisma', `Prisma model "${this.modelName}" not found on PrismaClient. Ensure your schema has the model defined.`);
41
+ }
42
+ return m;
43
+ }
44
+ // ── Storage Interface ─────────────────────────────────────────────────────
45
+ async get(key) {
46
+ try {
47
+ const record = (await this.model.findUnique({ where: { key } }));
48
+ if (!record)
49
+ return null;
50
+ return this._rowToRecord(record);
51
+ }
52
+ catch (err) {
53
+ throw createStorageError(key, this.name, err, this.clock);
54
+ }
55
+ }
56
+ async set(key, value, ttlMs) {
57
+ const now = this.clock();
58
+ const expiresAt = ttlMs !== undefined
59
+ ? BigInt(now + ttlMs)
60
+ : value.expiresAt !== undefined
61
+ ? BigInt(value.expiresAt)
62
+ : null;
63
+ const data = {
64
+ key,
65
+ status: value.status,
66
+ result: value.result !== undefined ? value.result : null,
67
+ payloadHash: value.payloadHash ?? null,
68
+ ownerToken: value.ownerToken ?? null,
69
+ attempts: value.attempts,
70
+ createdAt: BigInt(value.createdAt),
71
+ updatedAt: BigInt(value.updatedAt),
72
+ expiresAt,
73
+ };
74
+ try {
75
+ await this.model.upsert({
76
+ where: { key },
77
+ create: data,
78
+ update: {
79
+ status: data.status,
80
+ result: data.result,
81
+ payloadHash: data.payloadHash,
82
+ ownerToken: data.ownerToken,
83
+ attempts: data.attempts,
84
+ updatedAt: data.updatedAt,
85
+ expiresAt: data.expiresAt,
86
+ },
87
+ });
88
+ }
89
+ catch (err) {
90
+ throw createStorageError(key, this.name, err, this.clock);
91
+ }
92
+ }
93
+ async delete(key) {
94
+ try {
95
+ await this.model.delete({ where: { key } });
96
+ }
97
+ catch (err) {
98
+ // If record not found, that's acceptable
99
+ const code = err.code;
100
+ if (code === 'P2025')
101
+ return; // Prisma "record not found"
102
+ throw createStorageError(key, this.name, err, this.clock);
103
+ }
104
+ }
105
+ async compareAndSet(key, expectedOwnerToken, newValue, ttlMs) {
106
+ const now = this.clock();
107
+ const expiresAt = ttlMs !== undefined
108
+ ? BigInt(now + ttlMs)
109
+ : newValue.expiresAt !== undefined
110
+ ? BigInt(newValue.expiresAt)
111
+ : null;
112
+ try {
113
+ const result = await this.model.updateMany({
114
+ where: { key, ownerToken: expectedOwnerToken },
115
+ data: {
116
+ status: newValue.status,
117
+ result: newValue.result !== undefined ? newValue.result : null,
118
+ payloadHash: newValue.payloadHash ?? null,
119
+ ownerToken: newValue.ownerToken ?? null,
120
+ attempts: newValue.attempts,
121
+ updatedAt: BigInt(newValue.updatedAt),
122
+ expiresAt,
123
+ },
124
+ });
125
+ return result.count > 0;
126
+ }
127
+ catch (err) {
128
+ throw createStorageError(key, this.name, err, this.clock);
129
+ }
130
+ }
131
+ // ── Capabilities ──────────────────────────────────────────────────────────
132
+ capabilities() {
133
+ return {
134
+ transactions: this.useTransactions,
135
+ cas: true,
136
+ ttl: false,
137
+ advisoryLocks: false,
138
+ };
139
+ }
140
+ // ── Private ───────────────────────────────────────────────────────────────
141
+ _rowToRecord(row) {
142
+ return {
143
+ key: row.key,
144
+ status: row.status,
145
+ result: row.result,
146
+ payloadHash: row.payloadHash ?? undefined,
147
+ ownerToken: row.ownerToken ?? undefined,
148
+ attempts: row.attempts,
149
+ createdAt: Number(row.createdAt),
150
+ updatedAt: Number(row.updatedAt),
151
+ expiresAt: row.expiresAt !== null ? Number(row.expiresAt) : undefined,
152
+ };
153
+ }
154
+ }
155
+ // ─── Factory ──────────────────────────────────────────────────────────────────
156
+ /**
157
+ * Create a Prisma storage adapter.
158
+ *
159
+ * @example
160
+ * ```ts
161
+ * import { PrismaClient } from '@prisma/client';
162
+ * import { createPrismaAdapter } from '@periodic/vanadium/adapters/prisma';
163
+ *
164
+ * const prisma = new PrismaClient();
165
+ * const adapter = createPrismaAdapter({ prisma });
166
+ * ```
167
+ */
168
+ export function createPrismaAdapter(options) {
169
+ return new PrismaAdapter(options);
170
+ }
171
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapters/prisma/index.ts"],"names":[],"mappings":"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"}