@temboplus/afloat 0.2.1-beta.11 → 0.2.1-beta.13
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/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/modules/wallet/index.d.ts +1 -0
- package/dist/modules/wallet/wallet.repository.d.ts +15 -12
- package/dist/modules/wallet/wallet.timezone.d.ts +86 -0
- package/package.json +1 -1
|
@@ -147,16 +147,27 @@ export declare class WalletRepository extends BaseRepository<typeof contract> {
|
|
|
147
147
|
* The statement endpoint filters by calendar day, evaluated against
|
|
148
148
|
* the EAT-anchored database. Bounds are therefore *plain* date strings
|
|
149
149
|
* (`YYYY-MM-DD`), not full timestamps — sending a datetime gets
|
|
150
|
-
* rejected upstream.
|
|
151
|
-
*
|
|
150
|
+
* rejected upstream.
|
|
151
|
+
*
|
|
152
|
+
* When `timezone` is provided (and not EAT), `range` is interpreted as
|
|
153
|
+
* calendar days in that zone: the SDK pads the upstream EAT request
|
|
154
|
+
* by ±1 day and then post-filters entries whose `valueDate` (an
|
|
155
|
+
* absolute instant, parsed from the API's offset-carrying ISO string)
|
|
156
|
+
* falls outside the caller's window when rendered in `timezone`. The
|
|
157
|
+
* server's own filter is on `valueDate`, so this is consistent.
|
|
152
158
|
*
|
|
153
159
|
* @param props - The statement request properties
|
|
154
160
|
* @param props.wallet - The wallet to get statement for (preferred method)
|
|
155
161
|
* @param props.accountNo - Alternative: account number to lookup wallet and fetch statement
|
|
156
162
|
* @param props.range - Required date range. Both bounds are `YYYY-MM-DD`
|
|
157
|
-
* strings
|
|
163
|
+
* strings. Without `timezone`, they correspond to calendar days in
|
|
164
|
+
* EAT (unchanged legacy behavior). With `timezone`, they correspond
|
|
165
|
+
* to calendar days in that zone.
|
|
158
166
|
* @param props.range.startDate - Start of statement period (inclusive), `YYYY-MM-DD`
|
|
159
167
|
* @param props.range.endDate - End of statement period (inclusive), `YYYY-MM-DD`
|
|
168
|
+
* @param props.timezone - Optional IANA timezone id (e.g.
|
|
169
|
+
* `"America/New_York"`). When omitted or set to `"Africa/Nairobi"`,
|
|
170
|
+
* behavior is byte-identical to before this option existed.
|
|
160
171
|
* @returns Promise that resolves to an array of validated WalletStatementEntry instances with Narration objects
|
|
161
172
|
* @throws {Error} If neither wallet nor accountNo is provided
|
|
162
173
|
* @throws {Error} If accountNo is provided but no matching wallet is found
|
|
@@ -178,15 +189,6 @@ export declare class WalletRepository extends BaseRepository<typeof contract> {
|
|
|
178
189
|
* range: { startDate: "2024-01-01", endDate: "2024-01-31" },
|
|
179
190
|
* });
|
|
180
191
|
*
|
|
181
|
-
* // From a Date picker
|
|
182
|
-
* const entries = await repo.getStatement({
|
|
183
|
-
* wallet,
|
|
184
|
-
* range: {
|
|
185
|
-
* startDate: toPlainDate(pickedFromDate),
|
|
186
|
-
* endDate: toPlainDate(pickedToDate),
|
|
187
|
-
* },
|
|
188
|
-
* });
|
|
189
|
-
*
|
|
190
192
|
* // Process payout transactions
|
|
191
193
|
* const payoutEntries = entries.filter(entry => entry.isPayout);
|
|
192
194
|
* payoutEntries.forEach(entry => {
|
|
@@ -201,6 +203,7 @@ export declare class WalletRepository extends BaseRepository<typeof contract> {
|
|
|
201
203
|
};
|
|
202
204
|
wallet?: Wallet;
|
|
203
205
|
accountNo?: string;
|
|
206
|
+
timezone?: string;
|
|
204
207
|
}): Promise<WalletStatementEntry[]>;
|
|
205
208
|
/**
|
|
206
209
|
* Check if a wallet exists with the given query
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timezone helpers for the wallet statement flow.
|
|
3
|
+
*
|
|
4
|
+
* The statement endpoint accepts `YYYY-MM-DD` bounds and evaluates them
|
|
5
|
+
* against the EAT-anchored (UTC+3) database. To support a caller who
|
|
6
|
+
* wants "transactions whose `valueDate` falls on these calendar days in
|
|
7
|
+
* timezone `tz`", we:
|
|
8
|
+
*
|
|
9
|
+
* 1. Widen the EAT request by ±1 day, so the upstream window
|
|
10
|
+
* definitely contains every instant the caller cares about. ±1 is
|
|
11
|
+
* mathematically sufficient because the maximum delta from EAT
|
|
12
|
+
* (UTC+3) to any timezone on earth is 15 hours, comfortably under
|
|
13
|
+
* 24h.
|
|
14
|
+
* 2. After the response comes back, filter entries by `valueDate`
|
|
15
|
+
* rendered in the caller's zone, comparing as plain `YYYY-MM-DD`
|
|
16
|
+
* strings (which is correct because string-comparing two ISO
|
|
17
|
+
* calendar dates is equivalent to comparing the dates).
|
|
18
|
+
*
|
|
19
|
+
* The server's filter is on `valueDate` (verified empirically), so the
|
|
20
|
+
* client-side filter uses the same field — no risk of dropping records
|
|
21
|
+
* that were padded in.
|
|
22
|
+
*/
|
|
23
|
+
import type { PlainDate } from "./wallet.dtos.js";
|
|
24
|
+
/** IANA id for EAT. The SDK short-circuits all timezone work for this. */
|
|
25
|
+
export declare const EAT_TIMEZONE = "Africa/Nairobi";
|
|
26
|
+
/**
|
|
27
|
+
* Add or subtract whole calendar days from a `YYYY-MM-DD` string.
|
|
28
|
+
* Pure string-in/string-out, no dependency on the JS runtime's local
|
|
29
|
+
* timezone — we pin to UTC noon so DST cliffs and ±1s rounding can't
|
|
30
|
+
* tip the result onto an adjacent day.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* shiftPlainDate("2026-05-15", 1); // → "2026-05-16"
|
|
34
|
+
* shiftPlainDate("2026-05-15", -1); // → "2026-05-14"
|
|
35
|
+
* shiftPlainDate("2026-05-31", 1); // → "2026-06-01" (month wrap)
|
|
36
|
+
* shiftPlainDate("2026-01-01", -1); // → "2025-12-31" (year wrap)
|
|
37
|
+
* shiftPlainDate("2026-03-08", 1); // → "2026-03-09" (DST-safe; US "spring forward" day)
|
|
38
|
+
*/
|
|
39
|
+
export declare function shiftPlainDate(date: PlainDate, days: number): PlainDate;
|
|
40
|
+
/**
|
|
41
|
+
* Pad an EAT date range by ±1 day on each side. Used to ensure that an
|
|
42
|
+
* upstream EAT-anchored query returns every transaction that falls on
|
|
43
|
+
* the caller's local-zone window, regardless of timezone offset.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* padEatRange({ startDate: "2026-05-15", endDate: "2026-05-16" });
|
|
47
|
+
* // → { startDate: "2026-05-14", endDate: "2026-05-17" }
|
|
48
|
+
*
|
|
49
|
+
* padEatRange({ startDate: "2026-01-01", endDate: "2026-12-31" });
|
|
50
|
+
* // → { startDate: "2025-12-31", endDate: "2027-01-01" } (year wraps on both ends)
|
|
51
|
+
*/
|
|
52
|
+
export declare function padEatRange(range: {
|
|
53
|
+
startDate: PlainDate;
|
|
54
|
+
endDate: PlainDate;
|
|
55
|
+
}): {
|
|
56
|
+
startDate: PlainDate;
|
|
57
|
+
endDate: PlainDate;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Format an absolute instant as a `YYYY-MM-DD` string in the given
|
|
61
|
+
* IANA timezone. Uses `en-CA` locale because that's the one major
|
|
62
|
+
* locale whose default date format is already ISO-like — no need to
|
|
63
|
+
* stitch parts back together by hand.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* // A transaction's valueDate from the API ("+03:00" is EAT)
|
|
67
|
+
* const instant = new Date("2026-05-15T01:30:00+03:00");
|
|
68
|
+
*
|
|
69
|
+
* localDateInZone(instant, "Africa/Nairobi"); // → "2026-05-15"
|
|
70
|
+
* localDateInZone(instant, "UTC"); // → "2026-05-14" (22:30 prev day in UTC)
|
|
71
|
+
* localDateInZone(instant, "America/New_York"); // → "2026-05-14" (18:30 prev day in NY)
|
|
72
|
+
* localDateInZone(instant, "Pacific/Auckland"); // → "2026-05-15" (10:30 same day in NZ)
|
|
73
|
+
*/
|
|
74
|
+
export declare function localDateInZone(instant: Date, timezone: string): PlainDate;
|
|
75
|
+
/**
|
|
76
|
+
* True when the caller's selected timezone is effectively EAT. Used to
|
|
77
|
+
* short-circuit padding + post-filtering so existing EAT callers see
|
|
78
|
+
* byte-identical behavior.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* isEatTimezone(undefined); // → true (no zone = legacy EAT behavior)
|
|
82
|
+
* isEatTimezone("Africa/Nairobi"); // → true (canonical EAT id)
|
|
83
|
+
* isEatTimezone("UTC"); // → false
|
|
84
|
+
* isEatTimezone("America/New_York"); // → false
|
|
85
|
+
*/
|
|
86
|
+
export declare function isEatTimezone(timezone: string | undefined): boolean;
|