@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 +13 -13
- package/README.md +32 -32
- package/dist/cli-options.d.ts +3 -0
- package/dist/cli-options.d.ts.map +1 -0
- package/dist/cli-options.js +35 -0
- package/dist/cli-options.js.map +1 -0
- package/dist/cli.js +11 -37
- package/dist/cli.js.map +1 -1
- package/dist/credit.d.ts +11 -3
- package/dist/credit.d.ts.map +1 -1
- package/dist/credit.js +182 -31
- package/dist/credit.js.map +1 -1
- package/dist/health.js +1 -1
- package/dist/import-sqlite.d.ts +1 -0
- package/dist/import-sqlite.d.ts.map +1 -1
- package/dist/import-sqlite.js +108 -7
- package/dist/import-sqlite.js.map +1 -1
- package/dist/migrations.d.ts +5 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +363 -174
- package/dist/migrations.js.map +1 -1
- package/dist/receipt.js +24 -24
- package/package.json +55 -49
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 `
|
|
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
|
|
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 @@
|
|
|
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
|
-
|
|
6
|
-
|
|
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
|
|
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(
|
|
43
|
+
throw new Error(usage());
|
|
39
44
|
}
|
|
40
45
|
}
|
|
41
|
-
function
|
|
42
|
-
|
|
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":";AACA,OAAO,EAAE,0BAA0B,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;
|
|
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,
|
|
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
|
|
5
|
+
export declare class PostgresCreditStore implements CreditPolicyStore, OutboxDeliveryStore {
|
|
6
6
|
private readonly handle;
|
|
7
7
|
constructor(config: PostgresCreditStoreConfig);
|
|
8
|
-
transaction<T>(handler: (transaction:
|
|
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>;
|
package/dist/credit.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credit.d.ts","sourceRoot":"","sources":["../src/credit.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,sBAAsB,EACtB,aAAa,EACb,mBAAmB,EACnB,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,uBAAuB,
|
|
1
|
+
{"version":3,"file":"credit.d.ts","sourceRoot":"","sources":["../src/credit.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,sBAAsB,EACtB,aAAa,EACb,mBAAmB,EACnB,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,mBAAmB,EACnB,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,uBAAuB,EAEvB,iBAAiB,EAEjB,4BAA4B,EAC5B,oBAAoB,EACpB,aAAa,EACb,kBAAkB,EAClB,sBAAsB,EACtB,4BAA4B,EAC5B,iBAAiB,EACjB,WAAW,EACX,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,YAAY,EACZ,UAAU,EACV,YAAY,EACb,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAKL,KAAK,wBAAwB,EAE9B,MAAM,iBAAiB,CAAC;AAqBzB,MAAM,WAAW,yBAA0B,SAAQ,wBAAwB;CAAG;AAE9E,qBAAa,mBAAoB,YAAW,iBAAiB,EAAE,mBAAmB;IAChF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;gBAE5B,MAAM,EAAE,yBAAyB;IAIvC,WAAW,CAAC,CAAC,EACjB,OAAO,EAAE,CAAC,WAAW,EAAE,4BAA4B,KAAK,OAAO,CAAC,CAAC,CAAC,GACjE,OAAO,CAAC,CAAC,CAAC;IAoBb,UAAU,CAAC,EAAE,EAAE,MAAM;IAGrB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;IAG1D,YAAY,CAAC,MAAM,CAAC,EAAE,mBAAmB;IAGzC,QAAQ,CAAC,EAAE,EAAE,MAAM;IAGnB,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM;IAG7B,QAAQ,CAAC,EAAE,EAAE,MAAM;IAGnB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;IAG5C,eAAe,CAAC,EAAE,EAAE,MAAM;IAG1B,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM;IAGlC,cAAc,CAAC,EAAE,EAAE,MAAM;IAGzB,gBAAgB,CAAC,MAAM,CAAC,EAAE,uBAAuB;IAGjD,aAAa,CAAC,EAAE,EAAE,MAAM;IAGxB,eAAe,CAAC,EAAE,EAAE,MAAM;IAG1B,iBAAiB,CAAC,SAAS,CAAC,EAAE,MAAM;IAGpC,iBAAiB,CAAC,SAAS,CAAC,EAAE,MAAM;IAGpC,cAAc,CAAC,EAAE,EAAE,MAAM;IAGzB,gBAAgB,CAAC,MAAM,CAAC,EAAE,iBAAiB;IAG3C,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;IAG/C,gBAAgB,CAAC,EAAE,EAAE,MAAM;IAG3B,kBAAkB,CAAC,SAAS,CAAC,EAAE,MAAM;IAGrC,qBAAqB,CAAC,EAAE,EAAE,MAAM;IAGhC,sCAAsC,CACpC,IAAI,EAAE,kBAAkB,CAAC,MAAM,CAAC,EAChC,OAAO,EAAE,MAAM,EACf,iBAAiB,EAAE,MAAM;IAQ3B,6BAA6B,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,MAAM,EAAE;IAGpE,uBAAuB,CAAC,eAAe,CAAC,EAAE,MAAM;IAGhD,cAAc,CAAC,EAAE,EAAE,MAAM;IAGzB,iBAAiB,CAAC,SAAS,CAAC,EAAE,MAAM;IAGpC,YAAY,CAAC,EAAE,EAAE,MAAM;IAGvB,cAAc,CAAC,MAAM,CAAC,EAAE,eAAe;IAGvC,wBAAwB,CAAC,aAAa,CAAC,EAAE,MAAM;IAG/C,yBAAyB,CAAC,EAAE,EAAE,MAAM;IAGpC,mCAAmC,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAO1F,2BAA2B,CAAC,MAAM,CAAC,EAAE,4BAA4B;IAI3D,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAyB9E,mBAAmB,CACvB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC;IAYV,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBjE,oBAAoB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAIhE,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW/D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B;AAouBD,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,yBAAyB,GAAG,mBAAmB,CAEhG"}
|
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) {
|