@festapp/banksync 0.0.0-bootstrap.20260831
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 +21 -0
- package/README.md +155 -0
- package/dist/chunk-5QXHZGAW.js +696 -0
- package/dist/chunk-PBN2BUNR.cjs +696 -0
- package/dist/cloudflare.cjs +3768 -0
- package/dist/cloudflare.d.cts +84 -0
- package/dist/cloudflare.d.ts +84 -0
- package/dist/cloudflare.js +3768 -0
- package/dist/index.cjs +42 -0
- package/dist/index.d.cts +121 -0
- package/dist/index.d.ts +121 -0
- package/dist/index.js +42 -0
- package/dist/types-Cb5l2lXq.d.cts +86 -0
- package/dist/types-Cb5l2lXq.d.ts +86 -0
- package/migrations/0001_schema.sql +220 -0
- package/migrations/0010_security_hardening.sql +7 -0
- package/package.json +68 -0
- package/scripts/decrypt-backup.mjs +32 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Festapp
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# BankSync
|
|
2
|
+
|
|
3
|
+
BankSync turns bank transaction notifications into durable, signed webhooks.
|
|
4
|
+
It is a TypeScript package and a deployable Cloudflare Worker maintained by
|
|
5
|
+
[Festapp](https://github.com/festappnet).
|
|
6
|
+
|
|
7
|
+
The included Worker supports:
|
|
8
|
+
|
|
9
|
+
- Fio Bank notification email and Fio API ingestion;
|
|
10
|
+
- Air Bank notification email ingestion;
|
|
11
|
+
- MIME parsing, sender allowlisting and per-account pairing addresses;
|
|
12
|
+
- layered transaction deduplication in Cloudflare D1;
|
|
13
|
+
- durable webhook delivery through Cloudflare Queues with retry and healing;
|
|
14
|
+
- encrypted webhook secrets, audit records, retention and optional R2 backups.
|
|
15
|
+
|
|
16
|
+
## Install as a package
|
|
17
|
+
|
|
18
|
+
`v0.1.0` is an unsafe preview and must not be used in production. Install only
|
|
19
|
+
the latest version published to npm by the protected release workflow after its
|
|
20
|
+
checksum and provenance are available:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pnpm add @festapp/banksync
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The root export contains runtime-neutral parsing and webhook helpers:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import {
|
|
30
|
+
detectProvider,
|
|
31
|
+
parseEmail,
|
|
32
|
+
verifyWebhook,
|
|
33
|
+
type WebhookEnvelope,
|
|
34
|
+
} from "@festapp/banksync";
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The Cloudflare Worker is a separate export so importing the core does not pull
|
|
38
|
+
Cloudflare bindings into application code:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
export { default } from "@festapp/banksync/cloudflare";
|
|
42
|
+
export type { Env } from "@festapp/banksync/cloudflare";
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Deploy to Cloudflare
|
|
46
|
+
|
|
47
|
+
1. Clone this repository and install dependencies with `pnpm install`.
|
|
48
|
+
2. Copy `wrangler.example.toml` to `wrangler.toml` and replace every placeholder.
|
|
49
|
+
3. Create the D1 database, queues and optional R2 bucket named in the config.
|
|
50
|
+
4. For a fresh database apply the baseline; for an existing production database
|
|
51
|
+
whose history ends at `0009`, apply only `0010_security_hardening.sql` through
|
|
52
|
+
a scoped reviewed migration operation.
|
|
53
|
+
5. Set `ADMIN_SECRET`, `WEBHOOK_KEK`, `ENCRYPTION_KEY_V1`, and the active
|
|
54
|
+
`BACKUP_ENCRYPTION_KEY_Vn` with
|
|
55
|
+
`pnpm wrangler secret put <NAME>`.
|
|
56
|
+
6. Configure `CALLBACK_HOST_ALLOWLIST` with exact consumer hostnames. Production
|
|
57
|
+
refuses an empty allowlist, credentials, IP literals, special-use hosts,
|
|
58
|
+
fragments, suffix matches, and redirects.
|
|
59
|
+
7. Inspect one sanitized accepted and rejected Cloudflare message to establish
|
|
60
|
+
the Cloudflare-owned Authentication-Results authserv-id, then configure it as
|
|
61
|
+
`EMAIL_AUTHSERV_ID`. Email ingest intentionally remains disabled while it is
|
|
62
|
+
absent; MIME headers are never an identity fallback.
|
|
63
|
+
8. Run the release gates and deploy the exact attested artifact.
|
|
64
|
+
|
|
65
|
+
All three key families must be independent random 32-byte base64 values.
|
|
66
|
+
`BACKUP_ENCRYPTION_KEY_VERSION` selects the active backup key. Store backup
|
|
67
|
+
keys outside R2 and test restore before rotation. Never commit `wrangler.toml`,
|
|
68
|
+
`.dev.vars`, bank API tokens, backup keys, or consumer webhook secrets.
|
|
69
|
+
|
|
70
|
+
### Migration baseline
|
|
71
|
+
|
|
72
|
+
Fresh databases are created from the single canonical schema baseline
|
|
73
|
+
`migrations/0001_schema.sql` (schema version 10). The original incremental
|
|
74
|
+
`0001`–`0009` history remains recorded in existing D1 databases but is not
|
|
75
|
+
needed to create a new deployment. To stay compatible with those databases,
|
|
76
|
+
production upgrade is `0010_security_hardening.sql`; all future migrations must
|
|
77
|
+
start at `0011` or higher. Never renumber
|
|
78
|
+
or replace the baseline filename.
|
|
79
|
+
|
|
80
|
+
BankSync's D1 schema is intentionally independent of any consumer's billing
|
|
81
|
+
database. Billing settlement belongs behind each consumer's signed webhook
|
|
82
|
+
endpoint, so installing BankSync never creates or changes Mendelio/Supabase
|
|
83
|
+
billing tables or routines.
|
|
84
|
+
|
|
85
|
+
For local development, copy `.dev.vars.example` to `.dev.vars`, use placeholder
|
|
86
|
+
Cloudflare resource identifiers in `wrangler.toml`, apply migrations locally,
|
|
87
|
+
and run `pnpm dev`.
|
|
88
|
+
|
|
89
|
+
## Webhook contract
|
|
90
|
+
|
|
91
|
+
BankSync sends `transaction.received` version `1`. `delivery_id` is stable
|
|
92
|
+
across retries and is the consumer idempotency key. Each request includes:
|
|
93
|
+
|
|
94
|
+
- `X-BankSync-Timestamp`
|
|
95
|
+
- `X-BankSync-Delivery-Id`
|
|
96
|
+
- `X-BankSync-Signature: sha256=<hex>`
|
|
97
|
+
|
|
98
|
+
The HMAC input is the exact byte sequence
|
|
99
|
+
`timestamp + "." + deliveryId + "." + bodyBytes`. Verify the raw body before
|
|
100
|
+
JSON parsing. `verifyWebhook` validates raw-body HMAC, timestamp syntax and
|
|
101
|
+
tolerance, delivery header/body equality, event, and event version, then returns
|
|
102
|
+
a typed verified envelope. It throws `WebhookVerificationError` with a stable
|
|
103
|
+
code. There is intentionally no HMAC-only public verifier.
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
import { verifyWebhook } from "@festapp/banksync";
|
|
107
|
+
|
|
108
|
+
const bodyBytes = new Uint8Array(await request.arrayBuffer());
|
|
109
|
+
const envelope = await verifyWebhook({
|
|
110
|
+
secret,
|
|
111
|
+
timestamp: request.headers.get("x-banksync-timestamp") ?? "",
|
|
112
|
+
deliveryId: request.headers.get("x-banksync-delivery-id") ?? "",
|
|
113
|
+
signature: request.headers.get("x-banksync-signature") ?? "",
|
|
114
|
+
bodyBytes,
|
|
115
|
+
});
|
|
116
|
+
// Atomically claim envelope.delivery_id in durable consumer storage before any
|
|
117
|
+
// billing or other side effect. The verifier cannot provide durable replay
|
|
118
|
+
// protection on its own.
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Trust boundaries and operations
|
|
122
|
+
|
|
123
|
+
- Cloudflare Email Routing is the trusted SMTP/envelope boundary. The Worker
|
|
124
|
+
requires one configured trusted auth result plus aligned DKIM or DMARC and
|
|
125
|
+
exact agreement between envelope and MIME identities.
|
|
126
|
+
- `bank_accounts.owner_app_id` is the tenant authorization authority. Only an
|
|
127
|
+
admin can create a cross-owner subscription.
|
|
128
|
+
- Public HTTP exposes only `GET /health` with `{ "ok": true }` or a stable
|
|
129
|
+
unavailable response. `/status` and `/health/deep` require admin auth.
|
|
130
|
+
- Callback delivery revalidates the current exact-host policy immediately before
|
|
131
|
+
every fetch and never follows redirects.
|
|
132
|
+
- Idempotency is scoped by principal, method, and canonical path. Credential
|
|
133
|
+
creation/rotation endpoints reject `Idempotency-Key` and never cache responses.
|
|
134
|
+
- R2 backups are AES-256-GCM `.sql.enc` envelopes. Ephemeral idempotency and
|
|
135
|
+
rate-limit tables are excluded. Decrypt to a new mode-0600 file without
|
|
136
|
+
printing plaintext:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
BACKUP_DECRYPTION_KEY='<base64 key>' \
|
|
140
|
+
node scripts/decrypt-backup.mjs backup.sql.enc restored.sql
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Development
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
pnpm check
|
|
147
|
+
pnpm pack --dry-run
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Provider-live tests are intentionally not part of the default suite and must
|
|
151
|
+
never be run with production bank credentials.
|
|
152
|
+
|
|
153
|
+
## License
|
|
154
|
+
|
|
155
|
+
MIT
|