@cheqd/studio 3.18.0-develop.1 → 3.18.0-develop.3

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 (39) hide show
  1. package/README.md +18 -4
  2. package/dist/controllers/api/account.d.ts +2 -2
  3. package/dist/controllers/api/account.d.ts.map +1 -1
  4. package/dist/controllers/api/account.js +99 -12
  5. package/dist/controllers/api/account.js.map +1 -1
  6. package/dist/database/cache/store.d.ts +7 -0
  7. package/dist/database/cache/store.d.ts.map +1 -1
  8. package/dist/database/cache/store.js +6 -0
  9. package/dist/database/cache/store.js.map +1 -1
  10. package/dist/database/entities/faucet-request.entity.d.ts +12 -3
  11. package/dist/database/entities/faucet-request.entity.d.ts.map +1 -1
  12. package/dist/database/entities/faucet-request.entity.js +34 -11
  13. package/dist/database/entities/faucet-request.entity.js.map +1 -1
  14. package/dist/database/migrations/1791500000001-studio-migrations.d.ts +7 -0
  15. package/dist/database/migrations/1791500000001-studio-migrations.d.ts.map +1 -0
  16. package/dist/database/migrations/1791500000001-studio-migrations.js +16 -0
  17. package/dist/database/migrations/1791500000001-studio-migrations.js.map +1 -0
  18. package/dist/database/migrations/1791500000002-studio-migrations.d.ts +7 -0
  19. package/dist/database/migrations/1791500000002-studio-migrations.d.ts.map +1 -0
  20. package/dist/database/migrations/1791500000002-studio-migrations.js +10 -0
  21. package/dist/database/migrations/1791500000002-studio-migrations.js.map +1 -0
  22. package/dist/database/types/types.d.ts.map +1 -1
  23. package/dist/database/types/types.js +6 -0
  24. package/dist/database/types/types.js.map +1 -1
  25. package/dist/helpers/faucet-quota.d.ts +56 -4
  26. package/dist/helpers/faucet-quota.d.ts.map +1 -1
  27. package/dist/helpers/faucet-quota.js +107 -6
  28. package/dist/helpers/faucet-quota.js.map +1 -1
  29. package/dist/services/api/faucet-request.d.ts +45 -6
  30. package/dist/services/api/faucet-request.d.ts.map +1 -1
  31. package/dist/services/api/faucet-request.js +156 -13
  32. package/dist/services/api/faucet-request.js.map +1 -1
  33. package/dist/static/swagger-api.json +0 -60
  34. package/dist/types/constants.d.ts +7 -0
  35. package/dist/types/constants.d.ts.map +1 -1
  36. package/dist/types/constants.js +27 -0
  37. package/dist/types/constants.js.map +1 -1
  38. package/example.env +10 -0
  39. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"1791500000001-studio-migrations.d.ts","sourceRoot":"","sources":["../../../src/database/migrations/1791500000001-studio-migrations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE1D,qBAAa,6BAA8B,YAAW,kBAAkB;IACvE,IAAI,SAAmC;IAE1B,EAAE,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAU3C,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAK1D"}
@@ -0,0 +1,16 @@
1
+ export class StudioMigrations1791500000001 {
2
+ name = 'StudioMigrations1791500000001';
3
+ async up(queryRunner) {
4
+ await queryRunner.query(`ALTER TABLE "faucetRequest" ADD "status" text NOT NULL DEFAULT 'completed'`);
5
+ await queryRunner.query(`ALTER TABLE "faucetRequest" ADD CONSTRAINT "CHK_faucetRequest_status" CHECK ("status" IN ('pending', 'completed', 'unknown', 'abandoned'))`);
6
+ await queryRunner.query(`ALTER TABLE "faucetRequest" ADD "completedAt" TIMESTAMP WITH TIME ZONE`);
7
+ // Rows that already exist were recorded after the faucet call, so they are completed
8
+ await queryRunner.query(`UPDATE "faucetRequest" SET "completedAt" = "createdAt" WHERE "completedAt" IS NULL`);
9
+ }
10
+ async down(queryRunner) {
11
+ await queryRunner.query(`ALTER TABLE "faucetRequest" DROP COLUMN "completedAt"`);
12
+ await queryRunner.query(`ALTER TABLE "faucetRequest" DROP CONSTRAINT "CHK_faucetRequest_status"`);
13
+ await queryRunner.query(`ALTER TABLE "faucetRequest" DROP COLUMN "status"`);
14
+ }
15
+ }
16
+ //# sourceMappingURL=1791500000001-studio-migrations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"1791500000001-studio-migrations.js","sourceRoot":"","sources":["../../../src/database/migrations/1791500000001-studio-migrations.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,6BAA6B;IACzC,IAAI,GAAG,+BAA+B,CAAC;IAEhC,KAAK,CAAC,EAAE,CAAC,WAAwB;QACvC,MAAM,WAAW,CAAC,KAAK,CAAC,4EAA4E,CAAC,CAAC;QACtG,MAAM,WAAW,CAAC,KAAK,CACtB,4IAA4I,CAC5I,CAAC;QACF,MAAM,WAAW,CAAC,KAAK,CAAC,wEAAwE,CAAC,CAAC;QAClG,qFAAqF;QACrF,MAAM,WAAW,CAAC,KAAK,CAAC,oFAAoF,CAAC,CAAC;IAC/G,CAAC;IAEM,KAAK,CAAC,IAAI,CAAC,WAAwB;QACzC,MAAM,WAAW,CAAC,KAAK,CAAC,uDAAuD,CAAC,CAAC;QACjF,MAAM,WAAW,CAAC,KAAK,CAAC,wEAAwE,CAAC,CAAC;QAClG,MAAM,WAAW,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;IAC7E,CAAC;CACD"}
@@ -0,0 +1,7 @@
1
+ import { MigrationInterface, QueryRunner } from 'typeorm';
2
+ export declare class StudioMigrations1791500000002 implements MigrationInterface {
3
+ name: string;
4
+ up(queryRunner: QueryRunner): Promise<void>;
5
+ down(queryRunner: QueryRunner): Promise<void>;
6
+ }
7
+ //# sourceMappingURL=1791500000002-studio-migrations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"1791500000002-studio-migrations.d.ts","sourceRoot":"","sources":["../../../src/database/migrations/1791500000002-studio-migrations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE1D,qBAAa,6BAA8B,YAAW,kBAAkB;IACvE,IAAI,SAAmC;IAE1B,EAAE,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3C,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAG1D"}
@@ -0,0 +1,10 @@
1
+ export class StudioMigrations1791500000002 {
2
+ name = 'StudioMigrations1791500000002';
3
+ async up(queryRunner) {
4
+ await queryRunner.query(`ALTER TABLE "faucetRequest" ALTER COLUMN "createdAt" SET DEFAULT now()`);
5
+ }
6
+ async down(queryRunner) {
7
+ await queryRunner.query(`ALTER TABLE "faucetRequest" ALTER COLUMN "createdAt" DROP DEFAULT`);
8
+ }
9
+ }
10
+ //# sourceMappingURL=1791500000002-studio-migrations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"1791500000002-studio-migrations.js","sourceRoot":"","sources":["../../../src/database/migrations/1791500000002-studio-migrations.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,6BAA6B;IACzC,IAAI,GAAG,+BAA+B,CAAC;IAEhC,KAAK,CAAC,EAAE,CAAC,WAAwB;QACvC,MAAM,WAAW,CAAC,KAAK,CAAC,wEAAwE,CAAC,CAAC;IACnG,CAAC;IAEM,KAAK,CAAC,IAAI,CAAC,WAAwB;QACzC,MAAM,WAAW,CAAC,KAAK,CAAC,mEAAmE,CAAC,CAAC;IAC9F,CAAC;CACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/database/types/types.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AA+DrC,MAAM,WAAW,gBAAgB;IAChC,KAAK,IAAI,UAAU,CAAC;CACpB;AAED,qBAAa,MAAO,YAAW,gBAAgB;IAC9C,KAAK,IAAI,UAAU;CAWnB;AAED,qBAAa,QAAS,YAAW,gBAAgB;IAChD,KAAK,IAAI,UAAU;CAqGnB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/database/types/types.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAiErC,MAAM,WAAW,gBAAgB;IAChC,KAAK,IAAI,UAAU,CAAC;CACpB;AAED,qBAAa,MAAO,YAAW,gBAAgB;IAC9C,KAAK,IAAI,UAAU;CAWnB;AAED,qBAAa,QAAS,YAAW,gBAAgB;IAChD,KAAK,IAAI,UAAU;CAyGnB"}
@@ -55,6 +55,8 @@ import { MigrationsStatusLists1762775396083 } from '../migrations/1762775396083-
55
55
  import { UpdateWriteCursors1762775500000 } from '../migrations/1762775500000-UpdateWriteCursors.js';
56
56
  import { StudioMigrations1766408271347 } from '../migrations/1766408271347-studio-migrations.js';
57
57
  import { StudioMigrations1791500000000 } from '../migrations/1791500000000-studio-migrations.js';
58
+ import { StudioMigrations1791500000001 } from '../migrations/1791500000001-studio-migrations.js';
59
+ import { StudioMigrations1791500000002 } from '../migrations/1791500000002-studio-migrations.js';
58
60
  dotenv.config();
59
61
  const { EXTERNAL_DB_CONNECTION_URL, EXTERNAL_DB_CERT } = process.env;
60
62
  export class Memory {
@@ -147,6 +149,10 @@ export class Postgres {
147
149
  StudioMigrations1766408271347,
148
150
  // Add faucetRequest table for the monthly faucet quota
149
151
  StudioMigrations1791500000000,
152
+ // Track whether each faucet request completed, so abandoned reservations can stop counting
153
+ StudioMigrations1791500000001,
154
+ // Let the database set faucetRequest.createdAt
155
+ StudioMigrations1791500000002,
150
156
  ],
151
157
  entities: [
152
158
  ...Entities,
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/database/types/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/database/types/types.ts"],"names":[],"mappings":"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"}
@@ -19,6 +19,23 @@ export declare function maxRequestableNcheq(roomUnderCapNcheq: bigint, quotaRema
19
19
  /** Remaining quota, never negative. */
20
20
  export declare function remainingQuota(usedNcheq: bigint, limitNcheq: bigint): bigint;
21
21
  export declare function buildFaucetQuotaSummary(usedNcheq: bigint, limitNcheq: bigint, window: FaucetQuotaWindow): FaucetQuotaSummary;
22
+ /** Rows older than this are past retention: the start of the calendar month `retentionMonths` months ago (UTC). */
23
+ export declare function retentionCutoff(now: Date, retentionMonths: number): Date;
24
+ /** Seconds the customer still has to wait before their next faucet request; 0 if one is allowed now. */
25
+ export declare function secondsUntilNextRequest(lastRequestAt: Date | null, minIntervalSeconds: number, now?: Date): number;
26
+ /** Room left under an address cap once its balance and requests still in flight are accounted for; never negative. */
27
+ export declare function addressRoomNcheq(capNcheq: bigint, currentBalanceNcheq: bigint, inFlightNcheq: bigint): bigint;
28
+ export interface FaucetAddressCap {
29
+ capNcheq: bigint;
30
+ currentBalanceNcheq: bigint;
31
+ settleSeconds: number;
32
+ }
33
+ export interface FaucetReserveOptions {
34
+ limitNcheq: bigint;
35
+ pendingTimeoutSeconds?: number;
36
+ minIntervalSeconds?: number;
37
+ addressCap?: FaucetAddressCap;
38
+ }
22
39
  export type FaucetReservation = {
23
40
  reserved: true;
24
41
  faucetRequestId: string;
@@ -26,18 +43,40 @@ export type FaucetReservation = {
26
43
  window: FaucetQuotaWindow;
27
44
  } | {
28
45
  reserved: false;
46
+ reason: 'quota_exceeded';
29
47
  usedNcheq: bigint;
30
48
  window: FaucetQuotaWindow;
49
+ } | {
50
+ reserved: false;
51
+ reason: 'too_frequent';
52
+ retryAfterSeconds: number;
53
+ window: FaucetQuotaWindow;
54
+ } | {
55
+ reserved: false;
56
+ reason: 'address_cap_exceeded';
57
+ roomNcheq: bigint;
58
+ window: FaucetQuotaWindow;
31
59
  };
32
60
  /** Storage for quota reservations; implemented by `FaucetRequestService` and faked in tests. */
33
61
  export interface FaucetQuotaLedger {
34
- reserve(customer: CustomerEntity, address: string, amountNcheq: bigint, limitNcheq: bigint): Promise<FaucetReservation>;
62
+ reserve(customer: CustomerEntity, address: string, amountNcheq: bigint, options: FaucetReserveOptions): Promise<FaucetReservation>;
35
63
  release(faucetRequestId: string): Promise<void>;
64
+ /** The faucet confirmed the credit. */
65
+ complete(faucetRequestId: string): Promise<void>;
66
+ /** The faucet call threw, so tokens may have been sent: keep counting this reservation permanently. */
67
+ markUnknown(faucetRequestId: string): Promise<void>;
36
68
  }
37
69
  export type FaucetCreditResult = {
38
70
  outcome: 'quota_exceeded';
39
71
  usedNcheq: bigint;
40
72
  window: FaucetQuotaWindow;
73
+ } | {
74
+ outcome: 'too_frequent';
75
+ retryAfterSeconds: number;
76
+ window: FaucetQuotaWindow;
77
+ } | {
78
+ outcome: 'address_cap_exceeded';
79
+ roomNcheq: bigint;
41
80
  } | {
42
81
  outcome: 'credited';
43
82
  usedNcheq: bigint;
@@ -47,12 +86,23 @@ export type FaucetCreditResult = {
47
86
  status: number;
48
87
  error: string;
49
88
  };
89
+ export type FaucetLogLevel = 'info' | 'warn' | 'error';
90
+ export type FaucetLogger = (level: FaucetLogLevel, event: string, fields: Record<string, unknown>) => void;
91
+ /**
92
+ * Writes one structured log line per faucet decision, e.g. `{"event":"faucet.quota_exceeded","customerId":"..."}`,
93
+ * so "why was this customer blocked?" and "where did this month's quota go?" can be answered from the logs.
94
+ * Amounts are ncheq strings. Pass another logger to creditWithinQuota to capture events in tests.
95
+ */
96
+ export declare const logFaucetEvent: FaucetLogger;
50
97
  /**
51
98
  * Reserves quota, calls the faucet, and settles the reservation.
52
- * - Quota does not fit: the faucet is not called.
99
+ * - Quota, minimum interval or address cap does not allow it: the faucet is not called.
53
100
  * - Faucet answers with an error status: it definitely did not credit the account, so the quota is released.
54
101
  * - Faucet call throws (e.g. a timeout): the outcome is unknown and tokens may have been sent, so the
55
- * reservation is kept (over-counting is safer than refunding quota for tokens that were credited).
102
+ * reservation is marked unknown and keeps counting for good (over-counting is safer than refunding quota
103
+ * for tokens that were credited).
104
+ * - Faucet confirms: the reservation is marked completed.
105
+ * Every outcome is logged through `log`.
56
106
  */
57
107
  export declare function creditWithinQuota(ledger: FaucetQuotaLedger, delegate: () => Promise<{
58
108
  status: number;
@@ -62,5 +112,7 @@ export declare function creditWithinQuota(ledger: FaucetQuotaLedger, delegate: (
62
112
  address: string;
63
113
  amountNcheq: bigint;
64
114
  limitNcheq: bigint;
65
- }): Promise<FaucetCreditResult>;
115
+ minIntervalSeconds?: number;
116
+ addressCap?: FaucetAddressCap;
117
+ }, log?: FaucetLogger): Promise<FaucetCreditResult>;
66
118
  //# sourceMappingURL=faucet-quota.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"faucet-quota.d.ts","sourceRoot":"","sources":["../../src/helpers/faucet-quota.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AAC9E,OAAO,KAAK,EAAuB,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAGnF;;;GAGG;AAEH,MAAM,WAAW,iBAAiB;IACjC,KAAK,EAAE,IAAI,CAAC;IACZ,QAAQ,EAAE,IAAI,CAAC;CACf;AAED,oDAAoD;AACpD,wBAAgB,oBAAoB,CAAC,GAAG,GAAE,IAAiB,GAAG,iBAAiB,CAO9E;AAED,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,EAAE,GAAG,GAAE,IAAiB,GAAG,MAAM,CAE3F;AAED,uFAAuF;AACvF,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAElG;AAED,sHAAsH;AACtH,wBAAgB,mBAAmB,CAAC,iBAAiB,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,GAAG,MAAM,CAGlG;AAED,uCAAuC;AACvC,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAE5E;AAED,wBAAgB,uBAAuB,CACtC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,iBAAiB,GACvB,kBAAkB,CAUpB;AAED,MAAM,MAAM,iBAAiB,GAC1B;IAAE,QAAQ,EAAE,IAAI,CAAC;IAAC,eAAe,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,GACzF;IAAE,QAAQ,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,CAAC;AAErE,gGAAgG;AAChG,MAAM,WAAW,iBAAiB;IACjC,OAAO,CACN,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GAChB,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC9B,OAAO,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAED,MAAM,MAAM,kBAAkB,GAC3B;IAAE,OAAO,EAAE,gBAAgB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,GAE3E;IAAE,OAAO,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,GACrE;IAAE,OAAO,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/D;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACtC,MAAM,EAAE,iBAAiB,EACzB,QAAQ,EAAE,MAAM,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,EAC1D,MAAM,EAAE;IAAE,QAAQ,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC5F,OAAO,CAAC,kBAAkB,CAAC,CAgB7B"}
1
+ {"version":3,"file":"faucet-quota.d.ts","sourceRoot":"","sources":["../../src/helpers/faucet-quota.ts"],"names":[],"mappings":"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"}
@@ -36,23 +36,124 @@ export function buildFaucetQuotaSummary(usedNcheq, limitNcheq, window) {
36
36
  resetsAt: window.resetsAt.toISOString(),
37
37
  };
38
38
  }
39
+ /** Rows older than this are past retention: the start of the calendar month `retentionMonths` months ago (UTC). */
40
+ export function retentionCutoff(now, retentionMonths) {
41
+ return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - retentionMonths, 1));
42
+ }
43
+ /** Seconds the customer still has to wait before their next faucet request; 0 if one is allowed now. */
44
+ export function secondsUntilNextRequest(lastRequestAt, minIntervalSeconds, now = new Date()) {
45
+ if (!lastRequestAt || minIntervalSeconds <= 0)
46
+ return 0;
47
+ const remainingMs = minIntervalSeconds * 1000 - (now.getTime() - lastRequestAt.getTime());
48
+ return remainingMs > 0 ? Math.ceil(remainingMs / 1000) : 0;
49
+ }
50
+ /** Room left under an address cap once its balance and requests still in flight are accounted for; never negative. */
51
+ export function addressRoomNcheq(capNcheq, currentBalanceNcheq, inFlightNcheq) {
52
+ const room = capNcheq - currentBalanceNcheq - inFlightNcheq;
53
+ return room > 0n ? room : 0n;
54
+ }
55
+ async function markUnknownBestEffort(ledger, faucetRequestId, log) {
56
+ try {
57
+ await ledger.markUnknown(faucetRequestId);
58
+ }
59
+ catch (error) {
60
+ log('error', 'faucet.mark_unknown_failed', {
61
+ reservationId: faucetRequestId,
62
+ error: error?.message ?? String(error),
63
+ });
64
+ }
65
+ }
66
+ /**
67
+ * Writes one structured log line per faucet decision, e.g. `{"event":"faucet.quota_exceeded","customerId":"..."}`,
68
+ * so "why was this customer blocked?" and "where did this month's quota go?" can be answered from the logs.
69
+ * Amounts are ncheq strings. Pass another logger to creditWithinQuota to capture events in tests.
70
+ */
71
+ export const logFaucetEvent = (level, event, fields) => {
72
+ console[level](JSON.stringify({ event, ...fields }));
73
+ };
74
+ const shorten = (text) => (text.length > 200 ? `${text.slice(0, 200)}...` : text);
39
75
  /**
40
76
  * Reserves quota, calls the faucet, and settles the reservation.
41
- * - Quota does not fit: the faucet is not called.
77
+ * - Quota, minimum interval or address cap does not allow it: the faucet is not called.
42
78
  * - Faucet answers with an error status: it definitely did not credit the account, so the quota is released.
43
79
  * - Faucet call throws (e.g. a timeout): the outcome is unknown and tokens may have been sent, so the
44
- * reservation is kept (over-counting is safer than refunding quota for tokens that were credited).
80
+ * reservation is marked unknown and keeps counting for good (over-counting is safer than refunding quota
81
+ * for tokens that were credited).
82
+ * - Faucet confirms: the reservation is marked completed.
83
+ * Every outcome is logged through `log`.
45
84
  */
46
- export async function creditWithinQuota(ledger, delegate, params) {
47
- const reservation = await ledger.reserve(params.customer, params.address, params.amountNcheq, params.limitNcheq);
85
+ export async function creditWithinQuota(ledger, delegate, params, log = logFaucetEvent) {
86
+ const base = {
87
+ customerId: params.customer.customerId,
88
+ address: params.address,
89
+ amountNcheq: params.amountNcheq.toString(),
90
+ };
91
+ const reservation = await ledger.reserve(params.customer, params.address, params.amountNcheq, {
92
+ limitNcheq: params.limitNcheq,
93
+ minIntervalSeconds: params.minIntervalSeconds,
94
+ addressCap: params.addressCap,
95
+ });
48
96
  if (!reservation.reserved) {
49
- return { outcome: 'quota_exceeded', usedNcheq: reservation.usedNcheq, window: reservation.window };
97
+ switch (reservation.reason) {
98
+ case 'too_frequent':
99
+ log('warn', 'faucet.too_frequent', { ...base, retryAfterSeconds: reservation.retryAfterSeconds });
100
+ return {
101
+ outcome: 'too_frequent',
102
+ retryAfterSeconds: reservation.retryAfterSeconds,
103
+ window: reservation.window,
104
+ };
105
+ case 'address_cap_exceeded':
106
+ log('warn', 'faucet.address_cap_exceeded', { ...base, roomNcheq: reservation.roomNcheq.toString() });
107
+ return { outcome: 'address_cap_exceeded', roomNcheq: reservation.roomNcheq };
108
+ default:
109
+ log('warn', 'faucet.quota_exceeded', {
110
+ ...base,
111
+ usedNcheq: reservation.usedNcheq.toString(),
112
+ limitNcheq: params.limitNcheq.toString(),
113
+ });
114
+ return { outcome: 'quota_exceeded', usedNcheq: reservation.usedNcheq, window: reservation.window };
115
+ }
116
+ }
117
+ const withReservation = { ...base, reservationId: reservation.faucetRequestId };
118
+ log('info', 'faucet.reserved', {
119
+ ...withReservation,
120
+ usedNcheq: reservation.usedNcheq.toString(),
121
+ limitNcheq: params.limitNcheq.toString(),
122
+ });
123
+ let faucet;
124
+ try {
125
+ faucet = await delegate();
126
+ }
127
+ catch (error) {
128
+ log('warn', 'faucet.unknown', {
129
+ ...withReservation,
130
+ error: shorten(error?.message ?? String(error)),
131
+ note: 'faucet call threw; tokens may have been sent, so the reservation keeps counting',
132
+ });
133
+ await markUnknownBestEffort(ledger, reservation.faucetRequestId, log);
134
+ throw error;
50
135
  }
51
- const faucet = await delegate();
52
136
  if (faucet.status !== 200) {
53
137
  await ledger.release(reservation.faucetRequestId);
138
+ log('warn', 'faucet.released', {
139
+ ...withReservation,
140
+ faucetStatus: faucet.status,
141
+ error: shorten(faucet.error),
142
+ });
54
143
  return { outcome: 'faucet_failed', status: faucet.status, error: faucet.error };
55
144
  }
145
+ try {
146
+ await ledger.complete(reservation.faucetRequestId);
147
+ log('info', 'faucet.completed', withReservation);
148
+ }
149
+ catch (error) {
150
+ // The tokens were sent, so do not fail the request. The reservation stays pending and keeps counting
151
+ // until it times out.
152
+ log('error', 'faucet.complete_failed', {
153
+ ...withReservation,
154
+ error: shorten(error?.message ?? String(error)),
155
+ });
156
+ }
56
157
  return {
57
158
  outcome: 'credited',
58
159
  usedNcheq: reservation.usedNcheq + params.amountNcheq,
@@ -1 +1 @@
1
- {"version":3,"file":"faucet-quota.js","sourceRoot":"","sources":["../../src/helpers/faucet-quota.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAYzC,oDAAoD;AACpD,MAAM,UAAU,oBAAoB,CAAC,MAAY,IAAI,IAAI,EAAE;IAC1D,MAAM,IAAI,GAAG,GAAG,CAAC,cAAc,EAAE,CAAC;IAClC,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;IAChC,OAAO;QACN,KAAK,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QACzC,QAAQ,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;KAChD,CAAC;AACH,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,iBAAiB,CAAC,MAAyB,EAAE,MAAY,IAAI,IAAI,EAAE;IAClF,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;AACnF,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,WAAW,CAAC,SAAiB,EAAE,cAAsB,EAAE,UAAkB;IACxF,OAAO,SAAS,GAAG,cAAc,IAAI,UAAU,CAAC;AACjD,CAAC;AAED,sHAAsH;AACtH,MAAM,UAAU,mBAAmB,CAAC,iBAAyB,EAAE,mBAA2B;IACzF,MAAM,MAAM,GAAG,iBAAiB,GAAG,mBAAmB,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,mBAAmB,CAAC;IACjG,OAAO,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;AAClC,CAAC;AAED,uCAAuC;AACvC,MAAM,UAAU,cAAc,CAAC,SAAiB,EAAE,UAAkB;IACnE,OAAO,SAAS,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,SAAS,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,uBAAuB,CACtC,SAAiB,EACjB,UAAkB,EAClB,MAAyB;IAEzB,MAAM,cAAc,GAAG,cAAc,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAC7D,MAAM,MAAM,GAAG,CAAC,KAAa,EAAuB,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC/G,OAAO;QACN,MAAM,EAAE,OAAO;QACf,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC;QACzB,IAAI,EAAE,MAAM,CAAC,SAAS,CAAC;QACvB,SAAS,EAAE,MAAM,CAAC,cAAc,CAAC;QACjC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE;KACvC,CAAC;AACH,CAAC;AAuBD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACtC,MAAyB,EACzB,QAA0D,EAC1D,MAA8F;IAE9F,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IACjH,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;QAC3B,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,CAAC;IACpG,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,QAAQ,EAAE,CAAC;IAChC,IAAI,MAAM,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC3B,MAAM,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC;QAClD,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;IACjF,CAAC;IACD,OAAO;QACN,OAAO,EAAE,UAAU;QACnB,SAAS,EAAE,WAAW,CAAC,SAAS,GAAG,MAAM,CAAC,WAAW;QACrD,MAAM,EAAE,WAAW,CAAC,MAAM;KAC1B,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"faucet-quota.js","sourceRoot":"","sources":["../../src/helpers/faucet-quota.ts"],"names":[],"mappings":"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"}
@@ -1,22 +1,61 @@
1
1
  import type { Repository } from 'typeorm';
2
2
  import type { CustomerEntity } from '../../database/entities/customer.entity.js';
3
3
  import { FaucetRequestEntity } from '../../database/entities/faucet-request.entity.js';
4
- import { type FaucetQuotaLedger, type FaucetReservation } from '../../helpers/faucet-quota.js';
4
+ import { type FaucetQuotaLedger, type FaucetQuotaWindow, type FaucetReservation, type FaucetReserveOptions } from '../../helpers/faucet-quota.js';
5
5
  export declare class FaucetRequestService implements FaucetQuotaLedger {
6
6
  faucetRequestRepository: Repository<FaucetRequestEntity>;
7
+ private lastRetentionCleanupAt;
7
8
  static instance: FaucetRequestService;
8
9
  constructor(repository?: Repository<FaucetRequestEntity>);
9
- /** Total ncheq requested by the customer since `since`, using the given manager (and so its transaction). */
10
+ /**
11
+ * The database's clock. `createdAt` is set by the database, so every comparison (month window, minimum interval,
12
+ * pending timeout, settle window, retention) must use its clock too, not the application's: instances with
13
+ * slightly different clocks would otherwise disagree about how old a row is. `clock_timestamp()` rather than
14
+ * `now()`, because inside a transaction `now()` stays at the start of the transaction, before any wait for the lock.
15
+ */
16
+ private static databaseNow;
17
+ private static pendingCutoff;
18
+ /**
19
+ * Total ncheq requested by the customer since `since`, using the given manager (and so its transaction).
20
+ * Completed and unknown requests always count; a pending one counts only until it is older than
21
+ * `pendingCutoff`, after which it is treated as abandoned.
22
+ */
10
23
  private static sumRequestedNcheq;
24
+ /** Total ncheq requested for one address since `since`, excluding abandoned reservations. */
25
+ private static sumRecentForAddress;
26
+ /** When the customer last made a faucet request, or null if never. */
27
+ private static lastRequestAt;
28
+ /**
29
+ * Seconds the customer must still wait before their next request (0 if allowed). This is a cheap read taken
30
+ * before any expensive work; `reserve` repeats the check under the lock so concurrent requests cannot slip through.
31
+ */
32
+ getSecondsUntilNextAllowed(customer: CustomerEntity, minIntervalSeconds: number, now?: Date): Promise<number>;
33
+ /** What the customer has requested in the current quota window, and the window itself (both on the database clock). */
34
+ getQuotaStatus(customer: CustomerEntity, now?: Date, pendingTimeoutSeconds?: number): Promise<{
35
+ usedNcheq: bigint;
36
+ window: FaucetQuotaWindow;
37
+ }>;
11
38
  /** Total ncheq requested by the customer in the current quota window. */
12
- getUsedNcheq(customer: CustomerEntity, now?: Date): Promise<bigint>;
39
+ getUsedNcheq(customer: CustomerEntity, now?: Date, pendingTimeoutSeconds?: number): Promise<bigint>;
13
40
  /**
14
- * Atomically checks the customer's monthly quota and, if the amount fits, records it.
41
+ * Atomically checks the customer's monthly quota and, if the amount fits, records it as pending.
15
42
  * A per-customer advisory lock serialises concurrent requests so they cannot overshoot the limit.
16
- * Call `release` if the upstream faucet call then definitely failed.
43
+ * Afterwards call `complete` when the faucet confirms, `release` if it definitely failed, or `markUnknown`
44
+ * if the call threw.
45
+ */
46
+ reserve(customer: CustomerEntity, address: string, amountNcheq: bigint, { limitNcheq, minIntervalSeconds, pendingTimeoutSeconds, addressCap, }: FaucetReserveOptions, nowOverride?: Date): Promise<FaucetReservation>;
47
+ /** Deletes faucet request rows older than the retention period. Returns how many were deleted. */
48
+ runRetentionCleanup(now?: Date, retentionMonths?: number): Promise<number>;
49
+ /**
50
+ * Runs the retention cleanup in the background, at most once an hour per process. Called from normal requests
51
+ * because Studio has no scheduler; it never delays or fails the request that triggered it.
17
52
  */
18
- reserve(customer: CustomerEntity, address: string, amountNcheq: bigint, limitNcheq: bigint, now?: Date): Promise<FaucetReservation>;
53
+ private maybeRunRetentionCleanup;
19
54
  /** Releases a reservation, e.g. when the upstream faucet reported that it did not credit the account. */
20
55
  release(faucetRequestId: string): Promise<void>;
56
+ /** The faucet confirmed the credit. Also applies to a reservation that was already marked abandoned. */
57
+ complete(faucetRequestId: string): Promise<void>;
58
+ /** The faucet call threw, so tokens may have been sent: keep counting this reservation permanently. */
59
+ markUnknown(faucetRequestId: string): Promise<void>;
21
60
  }
22
61
  //# sourceMappingURL=faucet-request.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"faucet-request.d.ts","sourceRoot":"","sources":["../../../src/services/api/faucet-request.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,UAAU,EAAE,MAAM,SAAS,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4CAA4C,CAAC;AACjF,OAAO,EAAE,mBAAmB,EAAE,MAAM,kDAAkD,CAAC;AAEvF,OAAO,EAGN,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,MAAM,+BAA+B,CAAC;AAEvC,qBAAa,oBAAqB,YAAW,iBAAiB;IACtD,uBAAuB,EAAE,UAAU,CAAC,mBAAmB,CAAC,CAAC;IAEhE,OAAc,QAAQ,uBAA8B;gBAExC,UAAU,CAAC,EAAE,UAAU,CAAC,mBAAmB,CAAC;IAKxD,6GAA6G;mBACxF,iBAAiB;IAUtC,yEAAyE;IAC5D,YAAY,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,GAAE,IAAiB,GAAG,OAAO,CAAC,MAAM,CAAC;IAK5F;;;;OAIG;IACU,OAAO,CACnB,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,GAAG,GAAE,IAAiB,GACpB,OAAO,CAAC,iBAAiB,CAAC;IAmB7B,yGAAyG;IAC5F,OAAO,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG5D"}
1
+ {"version":3,"file":"faucet-request.d.ts","sourceRoot":"","sources":["../../../src/services/api/faucet-request.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,UAAU,EAAE,MAAM,SAAS,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4CAA4C,CAAC;AACjF,OAAO,EAAE,mBAAmB,EAAE,MAAM,kDAAkD,CAAC;AAGvF,OAAO,EAON,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,MAAM,+BAA+B,CAAC;AAKvC,qBAAa,oBAAqB,YAAW,iBAAiB;IACtD,uBAAuB,EAAE,UAAU,CAAC,mBAAmB,CAAC,CAAC;IAChE,OAAO,CAAC,sBAAsB,CAAK;IAEnC,OAAc,QAAQ,uBAA8B;gBAExC,UAAU,CAAC,EAAE,UAAU,CAAC,mBAAmB,CAAC;IAKxD;;;;;OAKG;mBACkB,WAAW;IAMhC,OAAO,CAAC,MAAM,CAAC,aAAa;IAI5B;;;;OAIG;mBACkB,iBAAiB;IAmBtC,6FAA6F;mBACxE,mBAAmB;IAiBxC,sEAAsE;mBACjD,aAAa;IAUlC;;;OAGG;IACU,0BAA0B,CACtC,QAAQ,EAAE,cAAc,EACxB,kBAAkB,EAAE,MAAM,EAC1B,GAAG,CAAC,EAAE,IAAI,GACR,OAAO,CAAC,MAAM,CAAC;IAWlB,uHAAuH;IAC1G,cAAc,CAC1B,QAAQ,EAAE,cAAc,EACxB,GAAG,CAAC,EAAE,IAAI,EACV,qBAAqB,GAAE,MAAuC,GAC5D,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,iBAAiB,CAAA;KAAE,CAAC;IAa5D,yEAAyE;IAC5D,YAAY,CACxB,QAAQ,EAAE,cAAc,EACxB,GAAG,CAAC,EAAE,IAAI,EACV,qBAAqB,GAAE,MAAuC,GAC5D,OAAO,CAAC,MAAM,CAAC;IAIlB;;;;;OAKG;IACU,OAAO,CACnB,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,EACC,UAAU,EACV,kBAAsB,EACtB,qBAAsD,EACtD,UAAU,GACV,EAAE,oBAAoB,EACvB,WAAW,CAAC,EAAE,IAAI,GAChB,OAAO,CAAC,iBAAiB,CAAC;IAyE7B,kGAAkG;IACrF,mBAAmB,CAC/B,GAAG,CAAC,EAAE,IAAI,EACV,eAAe,GAAE,MAAwC,GACvD,OAAO,CAAC,MAAM,CAAC;IAYlB;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IAiBhC,yGAAyG;IAC5F,OAAO,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5D,wGAAwG;IAC3F,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO7D,uGAAuG;IAC1F,WAAW,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGhE"}