@resvary/postgres 0.5.0 → 0.7.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/LICENSE CHANGED
@@ -1,13 +1,13 @@
1
- Copyright 2025-2026 horn111
2
-
3
- Licensed under the Apache License, Version 2.0 (the "License");
4
- you may not use this file except in compliance with the License.
5
- You may obtain a copy of the License at
6
-
7
- https://www.apache.org/licenses/LICENSE-2.0
8
-
9
- Unless required by applicable law or agreed to in writing, software
10
- distributed under the License is distributed on an "AS IS" BASIS,
11
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- See the License for the specific language governing permissions and
13
- limitations under the License.
1
+ Copyright 2025-2026 horn111
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ https://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
package/README.md CHANGED
@@ -1,32 +1,32 @@
1
- # @resvary/postgres
2
-
3
- Postgres `CreditStore` and `ReceiptStore` implementations for Resvary multi-process deployments. Resvary supports PostgreSQL 16–18. Stores never migrate automatically.
4
-
5
- ```bash
6
- npm install @resvary/sdk @resvary/postgres
7
- DATABASE_URL=postgres://... npx resvary-postgres migrate
8
- ```
9
-
10
- ```ts
11
- import { createPostgresCreditStore } from '@resvary/postgres';
12
-
13
- const store = createPostgresCreditStore({ connectionString: process.env.DATABASE_URL! });
14
- // Use store with CreditLedger, then close the owned pool during shutdown.
15
- await store.close();
16
- ```
17
-
18
- Pass either `connectionString` or an existing `pg.Pool`. A store created from a connection string owns and closes its pool. A store given a pool never closes it.
19
-
20
- Credit transactions and bundled receipt ledger operations run at `SERIALIZABLE` isolation with bounded retry. Schema v2 adds database checks, foreign keys, and transaction-hash uniqueness. Apply migrations before starting application or worker processes.
21
-
22
- CLI commands:
23
-
24
- ```text
25
- resvary-postgres status
26
- resvary-postgres migrate
27
- resvary-postgres import-sqlite --sqlite .resvary/resvary.sqlite --dry-run
28
- resvary-postgres import-sqlite --sqlite .resvary/resvary.sqlite
29
- resvary-postgres verify-import --sqlite .resvary/resvary.sqlite
30
- ```
31
-
32
- SQLite import requires Node.js 24. Stop every writer before importing. Verification compares entity payloads, balances, ledger totals, and open reservations.
1
+ # @resvary/postgres
2
+
3
+ Postgres `CreditPolicyStore` and `ReceiptStore` implementations for Resvary multi-process deployments. Resvary supports PostgreSQL 16–18. Stores never migrate automatically.
4
+
5
+ ```bash
6
+ npm install @resvary/sdk @resvary/postgres
7
+ DATABASE_URL=postgres://... npx resvary-postgres migrate
8
+ ```
9
+
10
+ ```ts
11
+ import { createPostgresCreditStore } from '@resvary/postgres';
12
+
13
+ const store = createPostgresCreditStore({ connectionString: process.env.DATABASE_URL! });
14
+ // Use store with CreditLedger, then close the owned pool during shutdown.
15
+ await store.close();
16
+ ```
17
+
18
+ Pass either `connectionString` or an existing `pg.Pool`. A store created from a connection string owns and closes its pool. A store given a pool never closes it.
19
+
20
+ Credit transactions and bundled receipt ledger operations run at `SERIALIZABLE` isolation with bounded retry. Schema v3 adds grant policies, credit lots, reservation allocations, and guarded legacy backfill. Apply migrations before starting application or worker processes.
21
+
22
+ CLI commands:
23
+
24
+ ```text
25
+ resvary-postgres status
26
+ resvary-postgres migrate
27
+ resvary-postgres import-sqlite --sqlite .resvary/resvary.sqlite --dry-run
28
+ resvary-postgres import-sqlite --sqlite .resvary/resvary.sqlite
29
+ resvary-postgres verify-import --sqlite .resvary/resvary.sqlite
30
+ ```
31
+
32
+ SQLite import requires Node.js 24 and SQLite schema v5. Stop every writer before importing. Verification compares entity payloads, balances, ledger totals, lots, allocations, and open reservations.
@@ -0,0 +1,3 @@
1
+ export type PostgresCliOptions = Record<string, string | boolean>;
2
+ export declare function parsePostgresCliOptions(args: string[]): PostgresCliOptions;
3
+ //# sourceMappingURL=cli-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-options.d.ts","sourceRoot":"","sources":["../src/cli-options.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC;AAElE,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,kBAAkB,CA6B1E"}
@@ -0,0 +1,35 @@
1
+ export function parsePostgresCliOptions(args) {
2
+ const valueOptions = new Set(['schema', 'sqlite']);
3
+ const booleanOptions = new Set(['dry-run']);
4
+ const options = {};
5
+ for (let index = 0; index < args.length; index += 1) {
6
+ const arg = args[index];
7
+ if (!arg?.startsWith('--'))
8
+ throw new Error(`Unexpected argument: ${arg}`);
9
+ const separator = arg.indexOf('=');
10
+ const key = arg.slice(2, separator === -1 ? undefined : separator);
11
+ if (!valueOptions.has(key) && !booleanOptions.has(key)) {
12
+ throw new Error(`Unknown option: --${key}`);
13
+ }
14
+ const inlineValue = separator === -1 ? undefined : arg.slice(separator + 1);
15
+ const next = args[index + 1];
16
+ if (booleanOptions.has(key)) {
17
+ const candidate = inlineValue ?? (next === 'true' || next === 'false' ? next : undefined);
18
+ if (candidate !== undefined && candidate !== 'true' && candidate !== 'false') {
19
+ throw new Error(`--${key} must be true or false`);
20
+ }
21
+ options[key] = candidate === undefined ? true : candidate === 'true';
22
+ if (inlineValue === undefined && candidate !== undefined)
23
+ index += 1;
24
+ continue;
25
+ }
26
+ const value = inlineValue ?? next;
27
+ if (!value || value.startsWith('--'))
28
+ throw new Error(`--${key} requires a value`);
29
+ options[key] = value;
30
+ if (inlineValue === undefined)
31
+ index += 1;
32
+ }
33
+ return options;
34
+ }
35
+ //# sourceMappingURL=cli-options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-options.js","sourceRoot":"","sources":["../src/cli-options.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,uBAAuB,CAAC,IAAc;IACpD,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;IACnD,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAuB,EAAE,CAAC;IACvC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACpD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,GAAG,EAAE,CAAC,CAAC;QAC3E,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACnC,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACnE,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACvD,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;QAC9C,CAAC;QACD,MAAM,WAAW,GAAG,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;QAC5E,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QAC7B,IAAI,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC5B,MAAM,SAAS,GAAG,WAAW,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YAC1F,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,MAAM,IAAI,SAAS,KAAK,OAAO,EAAE,CAAC;gBAC7E,MAAM,IAAI,KAAK,CAAC,KAAK,GAAG,wBAAwB,CAAC,CAAC;YACpD,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,GAAG,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,KAAK,MAAM,CAAC;YACrE,IAAI,WAAW,KAAK,SAAS,IAAI,SAAS,KAAK,SAAS;gBAAE,KAAK,IAAI,CAAC,CAAC;YACrE,SAAS;QACX,CAAC;QACD,MAAM,KAAK,GAAG,WAAW,IAAI,IAAI,CAAC;QAClC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,KAAK,GAAG,mBAAmB,CAAC,CAAC;QACnF,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACrB,IAAI,WAAW,KAAK,SAAS;YAAE,KAAK,IAAI,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
package/dist/cli.js CHANGED
@@ -1,11 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import { getPostgresMigrationStatus, migratePostgres } from './index.js';
3
+ import { parsePostgresCliOptions } from './cli-options.js';
3
4
  async function main() {
4
5
  const [command, ...rest] = process.argv.slice(2);
5
- const options = parseOptions(rest);
6
- const connectionString = optionString(options, 'database-url') ?? process.env.DATABASE_URL;
6
+ if (command === '--help' || command === '-h' || command === 'help') {
7
+ process.stdout.write(`${usage()}\n`);
8
+ return;
9
+ }
10
+ const options = parsePostgresCliOptions(rest);
11
+ const connectionString = process.env.DATABASE_URL;
7
12
  if (!connectionString)
8
- throw new Error('DATABASE_URL or --database-url is required');
13
+ throw new Error('DATABASE_URL is required');
9
14
  const schema = optionString(options, 'schema') ?? process.env.RESVARY_POSTGRES_SCHEMA ?? 'public';
10
15
  const base = { connectionString, schema };
11
16
  switch (command) {
@@ -35,42 +40,11 @@ async function main() {
35
40
  return;
36
41
  }
37
42
  default:
38
- throw new Error('Usage: resvary-postgres <status|migrate|import-sqlite|verify-import> [--database-url URL] [--schema NAME] [--sqlite PATH] [--dry-run]');
43
+ throw new Error(usage());
39
44
  }
40
45
  }
41
- function parseOptions(args) {
42
- const valueOptions = new Set(['database-url', 'schema', 'sqlite']);
43
- const booleanOptions = new Set(['dry-run']);
44
- const options = {};
45
- for (let index = 0; index < args.length; index += 1) {
46
- const arg = args[index];
47
- if (!arg?.startsWith('--'))
48
- throw new Error(`Unexpected argument: ${arg}`);
49
- const separator = arg.indexOf('=');
50
- const key = arg.slice(2, separator === -1 ? undefined : separator);
51
- if (!valueOptions.has(key) && !booleanOptions.has(key)) {
52
- throw new Error(`Unknown option: --${key}`);
53
- }
54
- const inlineValue = separator === -1 ? undefined : arg.slice(separator + 1);
55
- const next = args[index + 1];
56
- if (booleanOptions.has(key)) {
57
- const candidate = inlineValue ?? (next === 'true' || next === 'false' ? next : undefined);
58
- if (candidate !== undefined && candidate !== 'true' && candidate !== 'false') {
59
- throw new Error(`--${key} must be true or false`);
60
- }
61
- options[key] = candidate === undefined ? true : candidate === 'true';
62
- if (inlineValue === undefined && candidate !== undefined)
63
- index += 1;
64
- continue;
65
- }
66
- const value = inlineValue ?? next;
67
- if (!value || value.startsWith('--'))
68
- throw new Error(`--${key} requires a value`);
69
- options[key] = value;
70
- if (inlineValue === undefined)
71
- index += 1;
72
- }
73
- return options;
46
+ function usage() {
47
+ return 'Usage: resvary-postgres <status|migrate|import-sqlite|verify-import> [--schema NAME] [--sqlite PATH] [--dry-run]';
74
48
  }
75
49
  function optionString(options, key) {
76
50
  const value = options[key];
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/dist/credit.d.ts CHANGED
@@ -1,11 +1,11 @@
1
- import type { ClaimOutboxEventsInput, CreditAccount, CreditBalanceFilter, CreditGrant, CreditOutboxEvent, CreditReservation, CreditReservationFilter, CreditStore, CreditStoreTransaction, FailOutboxEventInput, FundingIntent, FundingTransaction, IdempotencyRecord, LedgerEntry, MeterDefinition, OutboxDeliveryStore, OutboxEventFilter, PriceVersion, UsageEvent, UsageReceipt } from '@resvary/sdk/credits';
1
+ import type { ClaimOutboxEventsInput, CreditAccount, CreditBalanceFilter, CreditGrant, CreditGrantPolicy, CreditLot, CreditLotAllocation, CreditLotFilter, CreditOutboxEvent, CreditReservation, CreditReservationFilter, CreditPolicyStore, CreditPolicyStoreTransaction, FailOutboxEventInput, FundingIntent, FundingTransaction, GrantPolicyApplication, GrantPolicyApplicationFilter, IdempotencyRecord, LedgerEntry, MeterDefinition, OutboxDeliveryStore, OutboxEventFilter, PriceVersion, UsageEvent, UsageReceipt } from '@resvary/sdk/credits';
2
2
  import { type PostgresConnectionConfig } from './connection.js';
3
3
  export interface PostgresCreditStoreConfig extends PostgresConnectionConfig {
4
4
  }
5
- export declare class PostgresCreditStore implements CreditStore, OutboxDeliveryStore {
5
+ export declare class PostgresCreditStore implements CreditPolicyStore, OutboxDeliveryStore {
6
6
  private readonly handle;
7
7
  constructor(config: PostgresCreditStoreConfig);
8
- transaction<T>(handler: (transaction: CreditStoreTransaction) => Promise<T>): Promise<T>;
8
+ transaction<T>(handler: (transaction: CreditPolicyStoreTransaction) => Promise<T>): Promise<T>;
9
9
  getAccount(id: string): Promise<CreditAccount | undefined>;
10
10
  getAccountByCustomer(projectId: string, customerId: string): Promise<CreditAccount | undefined>;
11
11
  listAccounts(filter?: CreditBalanceFilter): Promise<CreditAccount[]>;
@@ -30,6 +30,14 @@ export declare class PostgresCreditStore implements CreditStore, OutboxDeliveryS
30
30
  getFundingTransactionByExternalPayment(rail: FundingTransaction['rail'], network: string, externalPaymentId: string): Promise<FundingTransaction | undefined>;
31
31
  getFundingTransactionByTxHash(network: string, txHash: `0x${string}`): Promise<FundingTransaction | undefined>;
32
32
  listFundingTransactions(fundingIntentId?: string): Promise<FundingTransaction[]>;
33
+ getGrantPolicy(id: string): Promise<CreditGrantPolicy | undefined>;
34
+ listGrantPolicies(projectId?: string): Promise<CreditGrantPolicy[]>;
35
+ getCreditLot(id: string): Promise<CreditLot | undefined>;
36
+ listCreditLots(filter?: CreditLotFilter): Promise<CreditLot[]>;
37
+ listCreditLotAllocations(reservationId?: string): Promise<CreditLotAllocation[]>;
38
+ getGrantPolicyApplication(id: string): Promise<GrantPolicyApplication | undefined>;
39
+ getGrantPolicyApplicationByIdentity(policyId: string, accountId: string, periodKey: string): Promise<GrantPolicyApplication | undefined>;
40
+ listGrantPolicyApplications(filter?: GrantPolicyApplicationFilter): Promise<GrantPolicyApplication[]>;
33
41
  claimOutboxEvents(input: ClaimOutboxEventsInput): Promise<CreditOutboxEvent[]>;
34
42
  completeOutboxEvent(eventId: string, workerId: string, deliveredAt: number, attemptCount?: number): Promise<void>;
35
43
  failOutboxEvent(input: FailOutboxEventInput): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"credit.d.ts","sourceRoot":"","sources":["../src/credit.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"credit.d.ts","sourceRoot":"","sources":["../src/credit.ts"],"names":[],"mappings":"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"}
package/dist/credit.js CHANGED
@@ -98,41 +98,65 @@ export class PostgresCreditStore {
98
98
  listFundingTransactions(fundingIntentId) {
99
99
  return reader(this.handle.pool, this.handle).listFundingTransactions(fundingIntentId);
100
100
  }
101
+ getGrantPolicy(id) {
102
+ return reader(this.handle.pool, this.handle).getGrantPolicy(id);
103
+ }
104
+ listGrantPolicies(projectId) {
105
+ return reader(this.handle.pool, this.handle).listGrantPolicies(projectId);
106
+ }
107
+ getCreditLot(id) {
108
+ return reader(this.handle.pool, this.handle).getCreditLot(id);
109
+ }
110
+ listCreditLots(filter) {
111
+ return reader(this.handle.pool, this.handle).listCreditLots(filter);
112
+ }
113
+ listCreditLotAllocations(reservationId) {
114
+ return reader(this.handle.pool, this.handle).listCreditLotAllocations(reservationId);
115
+ }
116
+ getGrantPolicyApplication(id) {
117
+ return reader(this.handle.pool, this.handle).getGrantPolicyApplication(id);
118
+ }
119
+ getGrantPolicyApplicationByIdentity(policyId, accountId, periodKey) {
120
+ return reader(this.handle.pool, this.handle).getGrantPolicyApplicationByIdentity(policyId, accountId, periodKey);
121
+ }
122
+ listGrantPolicyApplications(filter) {
123
+ return reader(this.handle.pool, this.handle).listGrantPolicyApplications(filter);
124
+ }
101
125
  async claimOutboxEvents(input) {
102
126
  const outbox = table(this.handle, 'resvary_outbox_events');
103
- const result = await this.handle.pool.query(`WITH candidates AS (
104
- SELECT id FROM ${outbox}
105
- WHERE ($5::text IS NULL OR project_id = $5)
106
- AND ((status = 'pending' AND next_attempt_at <= $1)
107
- OR (status = 'processing' AND lease_expires_at <= $1))
108
- ORDER BY next_attempt_at ASC, created_at ASC
109
- FOR UPDATE SKIP LOCKED
110
- LIMIT $2
111
- )
112
- UPDATE ${outbox} AS event
113
- SET status = 'processing', attempt_count = event.attempt_count + 1,
114
- lease_owner = $3, lease_expires_at = $1 + $4, last_attempt_at = $1
115
- FROM candidates
116
- WHERE event.id = candidates.id
117
- RETURNING event.payload::text AS payload, event.status, event.attempt_count,
118
- event.next_attempt_at::text, event.lease_owner, event.lease_expires_at::text,
127
+ const result = await this.handle.pool.query(`WITH candidates AS (
128
+ SELECT id FROM ${outbox}
129
+ WHERE ($5::text IS NULL OR project_id = $5)
130
+ AND ((status = 'pending' AND next_attempt_at <= $1)
131
+ OR (status = 'processing' AND lease_expires_at <= $1))
132
+ ORDER BY next_attempt_at ASC, created_at ASC
133
+ FOR UPDATE SKIP LOCKED
134
+ LIMIT $2
135
+ )
136
+ UPDATE ${outbox} AS event
137
+ SET status = 'processing', attempt_count = event.attempt_count + 1,
138
+ lease_owner = $3, lease_expires_at = $1 + $4, last_attempt_at = $1
139
+ FROM candidates
140
+ WHERE event.id = candidates.id
141
+ RETURNING event.payload::text AS payload, event.status, event.attempt_count,
142
+ event.next_attempt_at::text, event.lease_owner, event.lease_expires_at::text,
119
143
  event.last_attempt_at::text, event.last_error, event.delivered_at::text`, [input.now, input.limit, input.workerId, input.leaseMs, input.projectId ?? null]);
120
144
  return result.rows.map(parseOutboxRow);
121
145
  }
122
146
  async completeOutboxEvent(eventId, workerId, deliveredAt, attemptCount) {
123
- const result = await this.handle.pool.query(`UPDATE ${table(this.handle, 'resvary_outbox_events')}
124
- SET status = 'delivered', delivered_at = $3, next_attempt_at = $3,
125
- lease_owner = NULL, lease_expires_at = NULL, last_error = NULL
126
- WHERE id = $1 AND status = 'processing' AND lease_owner = $2
147
+ const result = await this.handle.pool.query(`UPDATE ${table(this.handle, 'resvary_outbox_events')}
148
+ SET status = 'delivered', delivered_at = $3, next_attempt_at = $3,
149
+ lease_owner = NULL, lease_expires_at = NULL, last_error = NULL
150
+ WHERE id = $1 AND status = 'processing' AND lease_owner = $2
127
151
  AND ($4::integer IS NULL OR attempt_count = $4)`, [eventId, workerId, deliveredAt, attemptCount ?? null]);
128
152
  if (result.rowCount !== 1)
129
153
  throw new Error(`Outbox lease lost for event ${eventId}`);
130
154
  }
131
155
  async failOutboxEvent(input) {
132
- const result = await this.handle.pool.query(`UPDATE ${table(this.handle, 'resvary_outbox_events')}
133
- SET status = $4, next_attempt_at = $5, lease_owner = NULL,
134
- lease_expires_at = NULL, last_error = $3
135
- WHERE id = $1 AND status = 'processing' AND lease_owner = $2
156
+ const result = await this.handle.pool.query(`UPDATE ${table(this.handle, 'resvary_outbox_events')}
157
+ SET status = $4, next_attempt_at = $5, lease_owner = NULL,
158
+ lease_expires_at = NULL, last_error = $3
159
+ WHERE id = $1 AND status = 'processing' AND lease_owner = $2
136
160
  AND ($6::integer IS NULL OR attempt_count = $6)`, [
137
161
  input.eventId,
138
162
  input.workerId,
@@ -148,9 +172,9 @@ export class PostgresCreditStore {
148
172
  return this.listOutboxEvents({ projectId, status: 'dead_letter' });
149
173
  }
150
174
  async requeueOutboxEvent(eventId, now) {
151
- const result = await this.handle.pool.query(`UPDATE ${table(this.handle, 'resvary_outbox_events')}
152
- SET status = 'pending', attempt_count = 0, next_attempt_at = $2,
153
- lease_owner = NULL, lease_expires_at = NULL, last_error = NULL, delivered_at = NULL
175
+ const result = await this.handle.pool.query(`UPDATE ${table(this.handle, 'resvary_outbox_events')}
176
+ SET status = 'pending', attempt_count = 0, next_attempt_at = $2,
177
+ lease_owner = NULL, lease_expires_at = NULL, last_error = NULL, delivered_at = NULL
154
178
  WHERE id = $1 AND status = 'dead_letter'`, [eventId, now]);
155
179
  if (result.rowCount !== 1)
156
180
  throw new Error(`Dead-letter event not found: ${eventId}`);
@@ -239,6 +263,30 @@ class PostgresCreditTransaction {
239
263
  listFundingTransactions(fundingIntentId) {
240
264
  return reader(this.client, this.handle).listFundingTransactions(fundingIntentId);
241
265
  }
266
+ getGrantPolicy(id) {
267
+ return reader(this.client, this.handle).getGrantPolicy(id);
268
+ }
269
+ listGrantPolicies(projectId) {
270
+ return reader(this.client, this.handle).listGrantPolicies(projectId);
271
+ }
272
+ getCreditLot(id) {
273
+ return reader(this.client, this.handle).getCreditLot(id);
274
+ }
275
+ listCreditLots(filter) {
276
+ return reader(this.client, this.handle).listCreditLots(filter);
277
+ }
278
+ listCreditLotAllocations(reservationId) {
279
+ return reader(this.client, this.handle).listCreditLotAllocations(reservationId);
280
+ }
281
+ getGrantPolicyApplication(id) {
282
+ return reader(this.client, this.handle).getGrantPolicyApplication(id);
283
+ }
284
+ getGrantPolicyApplicationByIdentity(policyId, accountId, periodKey) {
285
+ return reader(this.client, this.handle).getGrantPolicyApplicationByIdentity(policyId, accountId, periodKey);
286
+ }
287
+ listGrantPolicyApplications(filter) {
288
+ return reader(this.client, this.handle).listGrantPolicyApplications(filter);
289
+ }
242
290
  saveAccount(value) {
243
291
  return upsert(this.client, this.handle, 'resvary_credit_accounts', [
244
292
  'id',
@@ -367,6 +415,86 @@ class PostgresCreditTransaction {
367
415
  value.createdAt,
368
416
  ], value);
369
417
  }
418
+ saveGrantPolicy(value) {
419
+ return insert(this.client, this.handle, 'resvary_grant_policies', ['id', 'project_id', 'policy_key', 'version', 'created_at'], [value.id, value.projectId, value.key, value.version, value.createdAt], value);
420
+ }
421
+ saveCreditLot(value) {
422
+ return upsert(this.client, this.handle, 'resvary_credit_lots', [
423
+ 'id',
424
+ 'account_id',
425
+ 'project_id',
426
+ 'customer_id',
427
+ 'kind',
428
+ 'policy_id',
429
+ 'original_units',
430
+ 'available_units',
431
+ 'reserved_units',
432
+ 'consumed_units',
433
+ 'expired_units',
434
+ 'expires_at',
435
+ 'created_at',
436
+ ], [
437
+ value.id,
438
+ value.accountId,
439
+ value.projectId,
440
+ value.customerId,
441
+ value.kind,
442
+ value.policyId ?? null,
443
+ value.originalUnits,
444
+ value.availableUnits,
445
+ value.reservedUnits,
446
+ value.consumedUnits,
447
+ value.expiredUnits,
448
+ value.expiresAt ?? null,
449
+ value.createdAt,
450
+ ], value);
451
+ }
452
+ saveCreditLotAllocation(value) {
453
+ return upsert(this.client, this.handle, 'resvary_credit_lot_allocations', [
454
+ 'id',
455
+ 'reservation_id',
456
+ 'lot_id',
457
+ 'account_id',
458
+ 'allocated_units',
459
+ 'reserved_units',
460
+ 'consumed_units',
461
+ 'released_units',
462
+ 'expired_units',
463
+ 'created_at',
464
+ ], [
465
+ value.id,
466
+ value.reservationId,
467
+ value.lotId,
468
+ value.accountId,
469
+ value.allocatedUnits,
470
+ value.reservedUnits,
471
+ value.consumedUnits,
472
+ value.releasedUnits,
473
+ value.expiredUnits,
474
+ value.createdAt,
475
+ ], value);
476
+ }
477
+ saveGrantPolicyApplication(value) {
478
+ return insert(this.client, this.handle, 'resvary_grant_policy_applications', [
479
+ 'id',
480
+ 'policy_id',
481
+ 'account_id',
482
+ 'project_id',
483
+ 'customer_id',
484
+ 'policy_type',
485
+ 'period_key',
486
+ 'created_at',
487
+ ], [
488
+ value.id,
489
+ value.policyId,
490
+ value.accountId,
491
+ value.projectId,
492
+ value.customerId,
493
+ value.policyType,
494
+ value.periodKey,
495
+ value.createdAt,
496
+ ], value);
497
+ }
370
498
  }
371
499
  function reader(db, handle) {
372
500
  const t = (name) => table(handle, name);
@@ -413,11 +541,34 @@ function reader(db, handle) {
413
541
  getFundingTransactionByExternalPayment: (rail, network, externalPaymentId) => one(db, `SELECT payload::text AS payload FROM ${t('resvary_funding_transactions')} WHERE rail = $1 AND network = $2 AND external_payment_id_norm = $3`, [rail, network, externalPaymentId.toLowerCase()]),
414
542
  getFundingTransactionByTxHash: (network, txHash) => one(db, `SELECT payload::text AS payload FROM ${t('resvary_funding_transactions')} WHERE network = $1 AND tx_hash_norm = $2`, [network, txHash.toLowerCase()]),
415
543
  listFundingTransactions: (fundingIntentId) => all(db, `SELECT payload::text AS payload FROM ${t('resvary_funding_transactions')} ${fundingIntentId ? 'WHERE funding_intent_id = $1' : ''} ORDER BY created_at ASC`, fundingIntentId ? [fundingIntentId] : []),
544
+ getGrantPolicy: (id) => one(db, `SELECT payload::text AS payload FROM ${t('resvary_grant_policies')} WHERE id = $1`, [
545
+ id,
546
+ ]),
547
+ listGrantPolicies: (projectId) => all(db, `SELECT payload::text AS payload FROM ${t('resvary_grant_policies')}
548
+ ${projectId ? 'WHERE project_id = $1' : ''} ORDER BY created_at, version`, projectId ? [projectId] : []),
549
+ getCreditLot: (id) => one(db, `SELECT payload::text AS payload FROM ${t('resvary_credit_lots')} WHERE id = $1`, [
550
+ id,
551
+ ]),
552
+ listCreditLots: (filter = {}) => filteredAll(db, `SELECT payload::text AS payload FROM ${t('resvary_credit_lots')} ORDER BY created_at, id`, [], (value) => matchesBalanceFilter(value, filter) &&
553
+ (!filter.policyId || value.policyId === filter.policyId) &&
554
+ (!filter.kind || value.kind === filter.kind) &&
555
+ (filter.expiresBefore === undefined ||
556
+ (value.expiresAt !== undefined && value.expiresAt <= filter.expiresBefore))),
557
+ listCreditLotAllocations: (reservationId) => all(db, `SELECT payload::text AS payload FROM ${t('resvary_credit_lot_allocations')}
558
+ ${reservationId ? 'WHERE reservation_id = $1' : ''} ORDER BY created_at, id`, reservationId ? [reservationId] : []),
559
+ getGrantPolicyApplication: (id) => one(db, `SELECT payload::text AS payload FROM ${t('resvary_grant_policy_applications')} WHERE id = $1`, [id]),
560
+ getGrantPolicyApplicationByIdentity: (policyId, accountId, periodKey) => one(db, `SELECT payload::text AS payload FROM ${t('resvary_grant_policy_applications')}
561
+ WHERE policy_id = $1 AND account_id = $2 AND period_key = $3`, [policyId, accountId, periodKey]),
562
+ listGrantPolicyApplications: (filter = {}) => filteredAll(db, `SELECT payload::text AS payload FROM ${t('resvary_grant_policy_applications')}
563
+ ORDER BY created_at, id`, [], (value) => matchesBalanceFilter(value, filter) &&
564
+ (!filter.policyId || value.policyId === filter.policyId) &&
565
+ (!filter.policyType || value.policyType === filter.policyType) &&
566
+ (!filter.periodKey || value.periodKey === filter.periodKey)),
416
567
  };
417
568
  }
418
569
  function outboxSelect(tableName, suffix) {
419
- return `SELECT payload::text AS payload, status, attempt_count,
420
- next_attempt_at::text, lease_owner, lease_expires_at::text,
570
+ return `SELECT payload::text AS payload, status, attempt_count,
571
+ next_attempt_at::text, lease_owner, lease_expires_at::text,
421
572
  last_attempt_at::text, last_error, delivered_at::text FROM ${tableName} ${suffix}`;
422
573
  }
423
574
  function parseOutboxRow(row) {
@@ -448,7 +599,7 @@ async function filteredAll(db, sql, values, filter) {
448
599
  async function insert(db, handle, name, columns, values, payload, conflictColumns = ['id']) {
449
600
  const allColumns = [...columns, 'payload'];
450
601
  const params = allColumns.map((_, index) => `$${index + 1}`).join(', ');
451
- await db.query(`INSERT INTO ${table(handle, name)} (${allColumns.join(', ')}) VALUES (${params})
602
+ await db.query(`INSERT INTO ${table(handle, name)} (${allColumns.join(', ')}) VALUES (${params})
452
603
  ON CONFLICT (${conflictColumns.join(', ')}) DO NOTHING`, [...values, serializeReceiptStoreValue(payload)]);
453
604
  }
454
605
  async function upsert(db, handle, name, columns, values, payload) {
@@ -458,7 +609,7 @@ async function upsert(db, handle, name, columns, values, payload) {
458
609
  .filter((column) => column !== 'id')
459
610
  .map((column) => `${column} = EXCLUDED.${column}`)
460
611
  .join(', ');
461
- await db.query(`INSERT INTO ${table(handle, name)} (${allColumns.join(', ')}) VALUES (${params})
612
+ await db.query(`INSERT INTO ${table(handle, name)} (${allColumns.join(', ')}) VALUES (${params})
462
613
  ON CONFLICT (id) DO UPDATE SET ${updates}`, [...values, serializeReceiptStoreValue(payload)]);
463
614
  }
464
615
  function matchesBalanceFilter(value, filter) {