Milestone 3: NATS wait (gate 9), hash lookup, zappier timestamp, NS1 tunnel
Wait-via-NATS returns completed or pending+jobId (GATE 9). Mock SHA256
idempotent register + GET /hashes/{sha256}. Zappier commercial edge has
POST /v1/timestamp and hash-lookup. GATE 12 smoke (signup + wait) passes.
NS1 NATS is 127.0.0.1:4222 on 70.88.205.138; SSH tunnel :14222. Local
nats-server -js used for isolated tests. Activate app adds Echo Text.
Learned: JetStream on NS1 is loopback-only; do not bind 4222 public.
This commit is contained in:
parent
10c663cc0c
commit
51ae79b75f
75 changed files with 1114 additions and 123 deletions
|
|
@ -13,6 +13,8 @@ They are **imported, not yet wired**. Public Zapier traffic should eventually hi
|
|||
Original brief (features a–m): [docs/00-sources/workspace-brief.md](docs/00-sources/workspace-brief.md).
|
||||
Where each tree came from: [docs/00-sources/provenance.md](docs/00-sources/provenance.md).
|
||||
|
||||
**Tomorrow morning:** [docs/04-activate/SETUP-ZAPIER-DEVELOPER.md](docs/04-activate/SETUP-ZAPIER-DEVELOPER.md) — create a Zapier developer account and push **Add Numbers**.
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
|
|
@ -36,6 +38,10 @@ Gates (`npm run gate:N`) continue the middleware plan in [TODO.md](TODO.md). Pha
|
|||
| [docs/02-architecture/overview.md](docs/02-architecture/overview.md) | Adapter internals (imported) |
|
||||
| [docs/03-zapier/operations.md](docs/03-zapier/operations.md) | Platform nouns |
|
||||
| [research/README.md](research/README.md) | Imported Zapier vendor research |
|
||||
| [docs/04-activate/SETUP-ZAPIER-DEVELOPER.md](docs/04-activate/SETUP-ZAPIER-DEVELOPER.md) | **Morning: Zapier developer account + push Add Numbers** |
|
||||
| [docs/modules/README.md](docs/modules/README.md) | Per-module API sheets (params, callees, returns) |
|
||||
| [docs/models/README.md](docs/models/README.md) | Data models |
|
||||
| [docs/sphinx/_build/html/index.html](docs/sphinx/_build/html/index.html) | Sphinx HTML (rebuild: `npm run docs:sphinx`) |
|
||||
|
||||
## Environment (middleware)
|
||||
|
||||
|
|
|
|||
18
TODO.md
18
TODO.md
|
|
@ -378,10 +378,10 @@ npm run gate:8
|
|||
|
||||
### Tasks
|
||||
|
||||
- [ ] 9.1 API waits on job event (subscription or inbox) after enqueue watch
|
||||
- [ ] 9.2 Hard timeout returns `{ jobId, status: "pending" }` (document Zapier fallback)
|
||||
- [ ] 9.3 Tests: fast complete; timeout path; cancellation on client disconnect (if feasible)
|
||||
- [ ] 9.4 Docs update: wait semantics, Zapier multi-step fallback
|
||||
- [x] 9.1 API waits on job event (subscription or inbox) after enqueue watch
|
||||
- [x] 9.2 Hard timeout returns `{ jobId, status: "pending" }` (document Zapier fallback)
|
||||
- [x] 9.3 Tests: fast complete; timeout path; cancellation on client disconnect (if feasible)
|
||||
- [x] 9.4 Docs update: wait semantics, Zapier multi-step fallback
|
||||
|
||||
### GATE 9 — Wait path
|
||||
|
||||
|
|
@ -399,7 +399,7 @@ npm run gate:9
|
|||
|
||||
| Date | Result | Notes |
|
||||
|------|--------|-------|
|
||||
| | | |
|
||||
| 2026-09-09 | pass | wait via NATS + timeout pending; NS1 tunnel 70.88.205.138 |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -480,9 +480,9 @@ npm run gate:11
|
|||
|
||||
### Tasks
|
||||
|
||||
- [ ] 12.1 `docker-compose.yml`: middleware + NATS (+ optional mock Verae)
|
||||
- [ ] 12.2 Compose smoke script: health, auth, timestamp wait, webhook
|
||||
- [ ] 12.3 Debug mode runbook: reproduce a failed job with `DEBUG_VERAE=*`
|
||||
- [x] 12.1 `docker-compose.yml`: middleware + NATS (+ optional mock Verae)
|
||||
- [x] 12.2 Compose smoke script: health, auth, timestamp wait, webhook
|
||||
- [x] 12.3 Debug mode runbook: reproduce a failed job with `DEBUG_VERAE=*`
|
||||
- [ ] 12.4 Record sample traces in `docs/developer/debugging.md`
|
||||
|
||||
### GATE 12 — E2E local
|
||||
|
|
@ -502,7 +502,7 @@ npm run gate:12
|
|||
|
||||
| Date | Result | Notes |
|
||||
|------|--------|-------|
|
||||
| | | |
|
||||
| 2026-09-09 | pass | harness/scripts/smoke.sh health + signup + wait |
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ Source: [workspace-brief.md](../00-sources/workspace-brief.md). Owners after com
|
|||
|----|------------|-------|-------------------------|--------------------|
|
||||
| a | Customer gets own API key | zappier `/portal` signup + regen | Built (`x-api-key`) | No |
|
||||
| b | Billing after usage limit | zappier meter + credit + portal reload + Stripe + admin PO | Built | No |
|
||||
| c | Register SHA256 or return original timestamp + ref | verae middleware | Partial: `POST /zapier/v1/timestamp` → `jobId`. No idempotent hash key | `POST /api/timestamp` (`data`, `hashAlg`) → 202 `jobId` |
|
||||
| d | Lookup by SHA256 | verae mock (later) | Missing | No (verify is certificate; status is jobId) |
|
||||
| c | Register SHA256 or return original timestamp + ref | verae middleware mock + zappier `/v1/timestamp` | **Mock done** — second create returns original `jobId` + `existing: true` | Live OpenAPI still `data` only |
|
||||
| d | Lookup by SHA256 | `GET /zapier/v1/hashes/{sha256}` and zappier `/v1/hashes/{sha256}` | **Mock done** | No live Verae route |
|
||||
| e | Timestamp + public/private metadata | verae mock | Missing | No |
|
||||
| f | e + encrypted LTS binary | verae mock | Missing. Do not use zappier demo `/v1/storage` | No |
|
||||
| g | Share file/dir + decryption key | verae mock | Missing | No |
|
||||
|
|
|
|||
21
docs/02-architecture/nats-gateway.md
Normal file
21
docs/02-architecture/nats-gateway.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# NATS gateway
|
||||
|
||||
JetStream for job watch, events, and webhook delivery lives on **NS1** (`70.88.205.138`, host `NS1.GEORGELAMBERT.ORG`).
|
||||
|
||||
The client port is **not public**. `nats-server -js` listens on `127.0.0.1:4222` (monitoring `8222`) with JetStream enabled (NATS 2.11.17).
|
||||
|
||||
## Tunnel from this Mac
|
||||
|
||||
```bash
|
||||
ssh -fN -L 14222:127.0.0.1:4222 marchon@70.88.205.138
|
||||
export NATS_URL=nats://127.0.0.1:14222
|
||||
export NATS_ENABLED=true
|
||||
```
|
||||
|
||||
Local isolated tests use a laptop `nats-server -js -p 4222`.
|
||||
|
||||
## Streams created by middleware
|
||||
|
||||
`ZAPIER_JOBS`, `ZAPIER_EVENTS`, `ZAPIER_WEBHOOKS` (optional `ZAPIER_USAGE`).
|
||||
|
||||
Do not expose 4222 on `0.0.0.0` without auth; keep SSH tunnel or private network.
|
||||
|
|
@ -103,7 +103,7 @@ If `register` says the name is taken, use `"Verae Time Dev"` or `"VeraeTime"`.
|
|||
- **API Key** — leave **blank**.
|
||||
- **API base URL** — leave **blank**.
|
||||
- Test connection → should succeed (*Verae Time (Add Numbers)* / local mode).
|
||||
5. Choose action **Add Numbers**.
|
||||
5. Choose action **Add Numbers** (or **Echo Text**).
|
||||
6. Set **Number 1** = `2`, **Number 2** = `3`.
|
||||
7. **Test step**. You want:
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,13 @@ Running record of milestones. Ordered by dependency.
|
|||
| M4 | Sphinx + PDF for every module + 10 models | M3 | done |
|
||||
| M5 | Git checkin docs + lessons | M4 | this commit |
|
||||
| M6 | Integration hardening (`/v1/add` on zappier, Add Numbers local) | M2 | done for activate-now |
|
||||
| M7 | Ready-to-activate final checkin | M5 | this commit |
|
||||
| M7 | Ready-to-activate final checkin | M5 | done `10c663c` |
|
||||
| M8 | Phase 9 wait-via-NATS + tests | M7 | done |
|
||||
| M9 | Phase 12 smoke | M8 | done |
|
||||
| M10 | Hash idempotent register/lookup mock | M7 | done |
|
||||
| M11 | Zappier /v1/timestamp + hash-lookup | M10 | done |
|
||||
| M12 | NS1 NATS 70.88.205.138 via SSH tunnel | — | done |
|
||||
| M13 | Echo action on activate app | M7 | done |
|
||||
|
||||
## Learned (M1)
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ endobj
|
|||
endobj
|
||||
7 0 obj
|
||||
<<
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260909024418-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260909024418-04'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260909025402-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260909025402-04'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
|
|
@ -68,7 +68,7 @@ xref
|
|||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<e38cd4e3b12db9314a8a6cdfd05bcc34><e38cd4e3b12db9314a8a6cdfd05bcc34>]
|
||||
[<2f955ee0641a9f5c09cc35b2e18cf0bf><2f955ee0641a9f5c09cc35b2e18cf0bf>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 7 0 R
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ endobj
|
|||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260909024418-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260909024418-04'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260909025402-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260909025402-04'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
|
|
@ -62,7 +62,7 @@ xref
|
|||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<eb33f0ae6981c12449e5508c1221d03d><eb33f0ae6981c12449e5508c1221d03d>]
|
||||
[<9cae5edd3d4e0bcf06baee891a5999ff><9cae5edd3d4e0bcf06baee891a5999ff>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 6 0 R
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ endobj
|
|||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260909024418-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260909024418-04'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260909025402-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260909025402-04'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
|
|
@ -62,7 +62,7 @@ xref
|
|||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<e356e73e01b5bea5f656fc16dfd0b270><e356e73e01b5bea5f656fc16dfd0b270>]
|
||||
[<e59336adb7766dc7e628986470cb6a9f><e59336adb7766dc7e628986470cb6a9f>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 6 0 R
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ endobj
|
|||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260909024418-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260909024418-04'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260909025402-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260909025402-04'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
|
|
@ -62,7 +62,7 @@ xref
|
|||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<08dab07d9f5bd9cd434cb151f6b84b52><08dab07d9f5bd9cd434cb151f6b84b52>]
|
||||
[<19922f9449900f729a32c70fe4a164c4><19922f9449900f729a32c70fe4a164c4>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 6 0 R
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ endobj
|
|||
endobj
|
||||
7 0 obj
|
||||
<<
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260909024418-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260909024418-04'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260909025402-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260909025402-04'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
|
|
@ -68,7 +68,7 @@ xref
|
|||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<73bc4dd8168535f5f72a61a3ae8226cb><73bc4dd8168535f5f72a61a3ae8226cb>]
|
||||
[<1be202b4fec6e54a0454781367cd42da><1be202b4fec6e54a0454781367cd42da>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 7 0 R
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ endobj
|
|||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260909024418-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260909024418-04'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260909025402-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260909025402-04'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
|
|
@ -62,7 +62,7 @@ xref
|
|||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<fab0642124fc4550c20555ce3f6892e5><fab0642124fc4550c20555ce3f6892e5>]
|
||||
[<d4a492432643ad2a4084a0f340f7142d><d4a492432643ad2a4084a0f340f7142d>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 6 0 R
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ endobj
|
|||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260909024418-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260909024418-04'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260909025402-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260909025402-04'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
|
|
@ -62,7 +62,7 @@ xref
|
|||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<8ee03c12859ca5bbdda2373d43becfb5><8ee03c12859ca5bbdda2373d43becfb5>]
|
||||
[<30f5c8829cce51759bfaf173130abd2c><30f5c8829cce51759bfaf173130abd2c>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 6 0 R
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ endobj
|
|||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260909024418-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260909024418-04'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260909025402-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260909025402-04'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
|
|
@ -62,7 +62,7 @@ xref
|
|||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<7bcbdd69c5f87d3b17d28804fb2d17ec><7bcbdd69c5f87d3b17d28804fb2d17ec>]
|
||||
[<c181c74e37ebeffdb7bb103101eba033><c181c74e37ebeffdb7bb103101eba033>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 6 0 R
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ endobj
|
|||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260909024418-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260909024418-04'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260909025402-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260909025402-04'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
|
|
@ -62,7 +62,7 @@ xref
|
|||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<15b24e6977023f8f031ff632a7b75f3a><15b24e6977023f8f031ff632a7b75f3a>]
|
||||
[<b55af8c14874e3eb9c9101a8dd7fc1d9><b55af8c14874e3eb9c9101a8dd7fc1d9>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 6 0 R
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ endobj
|
|||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260909024418-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260909024418-04'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260909025402-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260909025402-04'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
|
|
@ -62,7 +62,7 @@ xref
|
|||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<6238e19d13481b62a4a5fa415f64c0ba><6238e19d13481b62a4a5fa415f64c0ba>]
|
||||
[<14925b40184e6843f15b1b917d7c0c9c><14925b40184e6843f15b1b917d7c0c9c>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 6 0 R
|
||||
|
|
|
|||
|
|
@ -43,7 +43,9 @@ One MD file per source module.
|
|||
- [verae-zapier-middleware/nats/connection](verae-zapier-middleware/nats/connection.md)
|
||||
- [verae-zapier-middleware/nats/publishers](verae-zapier-middleware/nats/publishers.md)
|
||||
- [verae-zapier-middleware/nats/subjects](verae-zapier-middleware/nats/subjects.md)
|
||||
- [verae-zapier-middleware/nats/wait](verae-zapier-middleware/nats/wait.md)
|
||||
- [verae-zapier-middleware/routes/authRoutes](verae-zapier-middleware/routes/authRoutes.md)
|
||||
- [verae-zapier-middleware/routes/hashRoutes](verae-zapier-middleware/routes/hashRoutes.md)
|
||||
- [verae-zapier-middleware/routes/index](verae-zapier-middleware/routes/index.md)
|
||||
- [verae-zapier-middleware/routes/statusRoutes](verae-zapier-middleware/routes/statusRoutes.md)
|
||||
- [verae-zapier-middleware/routes/tenantRoutes](verae-zapier-middleware/routes/tenantRoutes.md)
|
||||
|
|
@ -66,6 +68,7 @@ One MD file per source module.
|
|||
- [verae-zapier-middleware/workers/webhookWorker](verae-zapier-middleware/workers/webhookWorker.md)
|
||||
- [verae-activate/authentication](verae-activate/authentication.md)
|
||||
- [verae-activate/creates/add_numbers](verae-activate/creates/add_numbers.md)
|
||||
- [verae-activate/creates/echo](verae-activate/creates/echo.md)
|
||||
- [verae-activate/index](verae-activate/index.md)
|
||||
- [verae-zapier/authentication](verae-zapier/authentication.md)
|
||||
- [verae-zapier/creates/add_numbers](verae-zapier/creates/add_numbers.md)
|
||||
|
|
@ -74,5 +77,6 @@ One MD file per source module.
|
|||
- [verae-zapier/creates/timestamp_and_wait](verae-zapier/creates/timestamp_and_wait.md)
|
||||
- [verae-zapier/creates/verify_timestamp](verae-zapier/creates/verify_timestamp.md)
|
||||
- [verae-zapier/index](verae-zapier/index.md)
|
||||
- [verae-zapier/searches/hash_lookup](verae-zapier/searches/hash_lookup.md)
|
||||
- [verae-zapier/searches/job_status](verae-zapier/searches/job_status.md)
|
||||
- [verae-zapier/triggers/timestamp_completed](verae-zapier/triggers/timestamp_completed.md)
|
||||
|
|
|
|||
40
docs/modules/verae-activate/creates/echo.md
Normal file
40
docs/modules/verae-activate/creates/echo.md
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# `verae-activate/creates/echo`
|
||||
|
||||
**Package:** `verae-activate`
|
||||
**Source:** `packages/verae-activate/creates/echo.js`
|
||||
**Lines:** 30
|
||||
|
||||
## What this module is
|
||||
|
||||
Implementation module in `verae-activate`. The tables below are extracted from the source (signatures + JSDoc).
|
||||
|
||||
## Exports
|
||||
|
||||
`key`, `noun`, `display`, `label`, `description`
|
||||
|
||||
## Types / interfaces / classes
|
||||
|
||||
_None extracted._
|
||||
|
||||
## Functions
|
||||
|
||||
| Name | Parameters | Param types (JSDoc) | Returns | Calls (same file / helpers) |
|
||||
|------|------------|---------------------|---------|-----------------------------|
|
||||
| `perform` | `_z, bundle` | — | `unknown` | see Call graph |
|
||||
|
||||
## What it imports / requires
|
||||
|
||||
_No imports detected._
|
||||
|
||||
## Call graph (identifiers invoked)
|
||||
|
||||
`action`, `async`
|
||||
|
||||
Each identifier is a call site in this file. Follow the import list to see the defining module; open that module’s MD for parameter and return types.
|
||||
|
||||
## Return values (how to read this)
|
||||
|
||||
- HTTP route handlers return Express `res.json(...)` bodies (see route docs).
|
||||
- Zapier `perform` functions return a **single object** (creates) or an **array** (triggers/searches).
|
||||
- Pricing functions return integer **cents** on `Quote.totalCents`.
|
||||
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
**Package:** `verae-activate`
|
||||
**Source:** `packages/verae-activate/index.js`
|
||||
**Lines:** 21
|
||||
**Lines:** 23
|
||||
|
||||
## What this module is
|
||||
|
||||
|
|
@ -10,7 +10,7 @@ Implementation module in `verae-activate`. The tables below are extracted from t
|
|||
|
||||
## Exports
|
||||
|
||||
`version`, `platformVersion`, `authentication`, `creates`, `addNumbers`
|
||||
`version`, `platformVersion`, `authentication`, `creates`, `addNumbers`, `echo`
|
||||
|
||||
## Types / interfaces / classes
|
||||
|
||||
|
|
@ -24,6 +24,7 @@ _No top-level functions extracted._
|
|||
|
||||
- `./authentication`
|
||||
- `./creates/add_numbers`
|
||||
- `./creates/echo`
|
||||
- `./package.json`
|
||||
- `zapier-platform-core`
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
**Package:** `verae-zapier-middleware`
|
||||
**Source:** `packages/verae-zapier-middleware/src/clients/veraeClient.js`
|
||||
**Lines:** 288
|
||||
**Lines:** 351
|
||||
|
||||
## What this module is
|
||||
|
||||
|
|
@ -10,7 +10,7 @@ Implementation module in `verae-zapier-middleware`. The tables below are extract
|
|||
|
||||
## Exports
|
||||
|
||||
`veraeClient`, `clearMockJobs`
|
||||
`sha256Hex`, `veraeClient`, `clearMockJobs`
|
||||
|
||||
## Types / interfaces / classes
|
||||
|
||||
|
|
@ -20,11 +20,13 @@ _None extracted._
|
|||
|
||||
| Name | Parameters | Param types (JSDoc) | Returns | Calls (same file / helpers) |
|
||||
|------|------------|---------------------|---------|-----------------------------|
|
||||
| `sha256Hex` | `data` | data: `string` | `string` | see Call graph |
|
||||
| `delay` | `ms` | ms: `number` | `Promise<void>` | see Call graph |
|
||||
| `mockLogin` | `{ username, password }` | ms: `number` | `Promise<void>` | see Call graph |
|
||||
| `mockValidate` | `token` | — | `unknown` | see Call graph |
|
||||
| `mockCreateTimestamp` | `{ data, hashAlg }` | — | `unknown` | see Call graph |
|
||||
| `mockCreateTimestamp` | `{ data, hashAlg, sha256, publicMetadata, privateMetadata }` | — | `unknown` | see Call graph |
|
||||
| `mockGetStatus` | `jobId` | — | `unknown` | see Call graph |
|
||||
| `mockLookupHash` | `sha256` | — | `unknown` | see Call graph |
|
||||
| `mockVerify` | `{ certificate }` | — | `unknown` | see Call graph |
|
||||
| `request` | `path, { method = 'GET', token, body } = {}` | path: `string` | `Promise<any>` | see Call graph |
|
||||
| `clearMockJobs` | `(none)` | — | `void` | see Call graph |
|
||||
|
|
@ -37,6 +39,7 @@ _None extracted._
|
|||
| `login` | `credentials` |
|
||||
| `validate` | `token` |
|
||||
| `createTimestamp` | `token, body` |
|
||||
| `lookupHash` | `token, sha256` |
|
||||
| `createBatchTimestamp` | `token, body` |
|
||||
| `getStatus` | `token, jobId` |
|
||||
| `getBatchStatus` | `token, body` |
|
||||
|
|
@ -54,7 +57,7 @@ _None extracted._
|
|||
|
||||
## Call graph (identifiers invoked)
|
||||
|
||||
`net`, `createDebugger`, `delay`, `setTimeout`, `mockLogin`, `now`, `toISOString`, `randomUUID`, `includes`, `mockValidate`, `startsWith`, `replace`, `mockCreateTimestamp`, `set`, `get`, `mockGetStatus`, `mockVerify`, `request`, `debug`, `fetch`, `stringify`, `text`, `parse`, `error`, `client`, `login`, `validate`, `createTimestamp`, `createBatchTimestamp`, `push`, `getStatus`, `encodeURIComponent`, `getBatchStatus`, `verify`, `verifyBatch`, `getJobVerification`, `waitForJob`, `jobs`, `clearMockJobs`, `clear`
|
||||
`net`, `createDebugger`, `sha256Hex`, `createHash`, `update`, `digest`, `delay`, `setTimeout`, `mockLogin`, `now`, `toISOString`, `randomUUID`, `includes`, `mockValidate`, `startsWith`, `replace`, `mockCreateTimestamp`, `toLowerCase`, `get`, `set`, `mockGetStatus`, `mockLookupHash`, `mockVerify`, `request`, `debug`, `fetch`, `stringify`, `text`, `parse`, `error`, `client`, `login`, `validate`, `createTimestamp`, `lookupHash`, `createBatchTimestamp`, `push`, `getStatus`, `encodeURIComponent`, `getBatchStatus`, `verify`, `verifyBatch`, `getJobVerification`, `waitForJob`, `jobs`, `clearMockJobs`, `clear`
|
||||
|
||||
Each identifier is a call site in this file. Follow the import list to see the defining module; open that module’s MD for parameter and return types.
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
**Package:** `verae-zapier-middleware`
|
||||
**Source:** `packages/verae-zapier-middleware/src/config.js`
|
||||
**Lines:** 143
|
||||
**Lines:** 145
|
||||
|
||||
## What this module is
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
**Package:** `verae-zapier-middleware`
|
||||
**Source:** `packages/verae-zapier-middleware/src/nats/connection.js`
|
||||
**Lines:** 112
|
||||
**Lines:** 117
|
||||
|
||||
## What this module is
|
||||
|
||||
|
|
@ -10,7 +10,7 @@ Implementation module in `verae-zapier-middleware`. The tables below are extract
|
|||
|
||||
## Exports
|
||||
|
||||
`connectNats`, `ensureStreams`, `closeNats`, `getJetStream`, `isNatsConnected`
|
||||
`connectNats`, `getNatsConnection`, `ensureStreams`, `closeNats`, `getJetStream`, `isNatsConnected`
|
||||
|
||||
## Types / interfaces / classes
|
||||
|
||||
|
|
@ -21,6 +21,7 @@ _None extracted._
|
|||
| Name | Parameters | Param types (JSDoc) | Returns | Calls (same file / helpers) |
|
||||
|------|------------|---------------------|---------|-----------------------------|
|
||||
| `connectNats` | `url = config.natsUrl` | url: `string` | `Promise<{ nc: import('nats').NatsConnection, js: import('nats').JetStreamClient, jsm: import('nats').JetStreamManager ` — >} | see Call graph |
|
||||
| `getNatsConnection` | `(none)` | — | `import('nats').NatsConnection|null` | see Call graph |
|
||||
| `ensureStreams` | `manager` | manager: `import('nats').JetStreamManager` | `Promise<void>` | see Call graph |
|
||||
| `closeNats` | `(none)` | — | `Promise<void>` | see Call graph |
|
||||
| `getJetStream` | `(none)` | — | `import('nats').JetStreamClient|null` | see Call graph |
|
||||
|
|
@ -34,7 +35,7 @@ _None extracted._
|
|||
|
||||
## Call graph (identifiers invoked)
|
||||
|
||||
`createDebugger`, `import`, `connectNats`, `debug`, `disabled`, `info`, `connect`, `jetstream`, `jetstreamManager`, `ensureStreams`, `add`, `closeNats`, `drain`, `getJetStream`, `isNatsConnected`, `isClosed`
|
||||
`createDebugger`, `import`, `connectNats`, `debug`, `disabled`, `info`, `connect`, `jetstream`, `jetstreamManager`, `getNatsConnection`, `ensureStreams`, `add`, `closeNats`, `drain`, `getJetStream`, `isNatsConnected`, `isClosed`
|
||||
|
||||
Each identifier is a call site in this file. Follow the import list to see the defining module; open that module’s MD for parameter and return types.
|
||||
|
||||
|
|
|
|||
44
docs/modules/verae-zapier-middleware/nats/wait.md
Normal file
44
docs/modules/verae-zapier-middleware/nats/wait.md
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
# `verae-zapier-middleware/nats/wait`
|
||||
|
||||
**Package:** `verae-zapier-middleware`
|
||||
**Source:** `packages/verae-zapier-middleware/src/nats/wait.js`
|
||||
**Lines:** 60
|
||||
|
||||
## What this module is
|
||||
|
||||
Implementation module in `verae-zapier-middleware`. The tables below are extracted from the source (signatures + JSDoc).
|
||||
|
||||
## Exports
|
||||
|
||||
`waitForJobEvent`
|
||||
|
||||
## Types / interfaces / classes
|
||||
|
||||
_None extracted._
|
||||
|
||||
## Functions
|
||||
|
||||
| Name | Parameters | Param types (JSDoc) | Returns | Calls (same file / helpers) |
|
||||
|------|------------|---------------------|---------|-----------------------------|
|
||||
| `waitForJobEvent` | `jobId, timeoutMs` | jobId: `string`, timeoutMs: `number` | `Promise<object|null>` — event payload or null on timeout | see Call graph |
|
||||
| `firstMatch` | `async (` | — | `unknown` | see Call graph |
|
||||
|
||||
## What it imports / requires
|
||||
|
||||
- `../debug/logger.js`
|
||||
- `../debug/trace-context.js`
|
||||
- `./subjects.js`
|
||||
- `./connection.js`
|
||||
|
||||
## Call graph (identifiers invoked)
|
||||
|
||||
`createDebugger`, `waitForJobEvent`, `getNatsConnection`, `connectNats`, `subscribe`, `getTraceId`, `debug`, `setTimeout`, `resolve`, `async`, `parse`, `string`, `race`, `unsubscribe`
|
||||
|
||||
Each identifier is a call site in this file. Follow the import list to see the defining module; open that module’s MD for parameter and return types.
|
||||
|
||||
## Return values (how to read this)
|
||||
|
||||
- HTTP route handlers return Express `res.json(...)` bodies (see route docs).
|
||||
- Zapier `perform` functions return a **single object** (creates) or an **array** (triggers/searches).
|
||||
- Pricing functions return integer **cents** on `Quote.totalCents`.
|
||||
|
||||
46
docs/modules/verae-zapier-middleware/routes/hashRoutes.md
Normal file
46
docs/modules/verae-zapier-middleware/routes/hashRoutes.md
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# `verae-zapier-middleware/routes/hashRoutes`
|
||||
|
||||
**Package:** `verae-zapier-middleware`
|
||||
**Source:** `packages/verae-zapier-middleware/src/routes/hashRoutes.js`
|
||||
**Lines:** 22
|
||||
|
||||
## What this module is
|
||||
|
||||
Implementation module in `verae-zapier-middleware`. The tables below are extracted from the source (signatures + JSDoc).
|
||||
|
||||
## Exports
|
||||
|
||||
`hashRoutes`
|
||||
|
||||
## Types / interfaces / classes
|
||||
|
||||
_None extracted._
|
||||
|
||||
## Functions
|
||||
|
||||
_No top-level functions extracted._
|
||||
|
||||
## Methods (class / object)
|
||||
|
||||
| Name | Parameters |
|
||||
|------|------------|
|
||||
| `asyncHandler` | `async (req, res` |
|
||||
|
||||
## What it imports / requires
|
||||
|
||||
- `express`
|
||||
- `../errors.js`
|
||||
- `../services/timestampService.js`
|
||||
|
||||
## Call graph (identifiers invoked)
|
||||
|
||||
`get`, `asyncHandler`, `async`, `test`, `lookupHash`, `json`
|
||||
|
||||
Each identifier is a call site in this file. Follow the import list to see the defining module; open that module’s MD for parameter and return types.
|
||||
|
||||
## Return values (how to read this)
|
||||
|
||||
- HTTP route handlers return Express `res.json(...)` bodies (see route docs).
|
||||
- Zapier `perform` functions return a **single object** (creates) or an **array** (triggers/searches).
|
||||
- Pricing functions return integer **cents** on `Quote.totalCents`.
|
||||
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
**Package:** `verae-zapier-middleware`
|
||||
**Source:** `packages/verae-zapier-middleware/src/routes/index.js`
|
||||
**Lines:** 34
|
||||
**Lines:** 36
|
||||
|
||||
## What this module is
|
||||
|
||||
|
|
@ -29,6 +29,7 @@ _No top-level functions extracted._
|
|||
- `./statusRoutes.js`
|
||||
- `./webhookRoutes.js`
|
||||
- `./tenantRoutes.js`
|
||||
- `./hashRoutes.js`
|
||||
- `../middleware/authenticate.js`
|
||||
- `../middleware/rateLimit.js`
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
**Package:** `verae-zapier-middleware`
|
||||
**Source:** `packages/verae-zapier-middleware/src/routes/timestampRoutes.js`
|
||||
**Lines:** 50
|
||||
**Lines:** 62
|
||||
|
||||
## What this module is
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
**Package:** `verae-zapier-middleware`
|
||||
**Source:** `packages/verae-zapier-middleware/src/services/timestampService.js`
|
||||
**Lines:** 123
|
||||
**Lines:** 160
|
||||
|
||||
## What this module is
|
||||
|
||||
|
|
@ -10,7 +10,7 @@ Implementation module in `verae-zapier-middleware`. The tables below are extract
|
|||
|
||||
## Exports
|
||||
|
||||
`createTimestamp`, `createTimestampAndWait`, `createBatchTimestamp`, `getJobStatus`, `getBatchJobStatus`, `getJobVerification`
|
||||
`createTimestamp`, `createTimestampAndWait`, `createBatchTimestamp`, `getJobStatus`, `getBatchJobStatus`, `getJobVerification`, `lookupHash`
|
||||
|
||||
## Types / interfaces / classes
|
||||
|
||||
|
|
@ -21,12 +21,13 @@ _None extracted._
|
|||
| Name | Parameters | Param types (JSDoc) | Returns | Calls (same file / helpers) |
|
||||
|------|------------|---------------------|---------|-----------------------------|
|
||||
| `enqueueWatchForJob` | `ctx, jobId` | ctx: `object`, jobId: `string` | `unknown` | see Call graph |
|
||||
| `createTimestamp` | `ctx, body` | ctx: `object` | `Promise<{ jobId: string ` — >} | see Call graph |
|
||||
| `createTimestamp` | `ctx, body` | ctx: `object` | `Promise<{ jobId: string, sha256?: string, existing?: boolean ` — >} | see Call graph |
|
||||
| `createTimestampAndWait` | `ctx, body` | ctx: `object` | `Promise<object>` — StatusResponse | see Call graph |
|
||||
| `createBatchTimestamp` | `ctx, body` | ctx: `object` | `unknown` | see Call graph |
|
||||
| `getJobStatus` | `ctx, jobId` | ctx: `object`, jobId: `string` | `unknown` | see Call graph |
|
||||
| `getBatchJobStatus` | `ctx, body` | ctx: `object` | `unknown` | see Call graph |
|
||||
| `getJobVerification` | `ctx, jobId` | ctx: `object`, jobId: `string` | `unknown` | see Call graph |
|
||||
| `lookupHash` | `ctx, sha256` | ctx: `object`, sha256: `string` | `unknown` | see Call graph |
|
||||
|
||||
## Methods (class / object)
|
||||
|
||||
|
|
@ -40,12 +41,12 @@ _None extracted._
|
|||
}` |
|
||||
| `checkEntitlement` | `ctx.tenantId, 'timestamp'` |
|
||||
| `recordUsage` | `ctx.tenantId, 'timestamp'` |
|
||||
| `recordUsage` | `ctx.tenantId, 'status'` |
|
||||
| `checkEntitlement` | `ctx.tenantId, 'batch_timestamp', { amount: itemCount }` |
|
||||
| `recordUsage` | `ctx.tenantId, 'batch_timestamp', { amount: itemCount }` |
|
||||
| `recordUsage` | `ctx.tenantId, 'status'` |
|
||||
| `recordUsage` | `ctx.tenantId, 'status', { amount: body.jobIds?.length ?? 1 }` |
|
||||
| `recordUsage` | `ctx.tenantId, 'status'` |
|
||||
| `recordUsage` | `ctx.tenantId, 'status'` |
|
||||
|
||||
## What it imports / requires
|
||||
|
||||
|
|
@ -58,7 +59,7 @@ _None extracted._
|
|||
|
||||
## Call graph (identifiers invoked)
|
||||
|
||||
`createDebugger`, `enqueueWatchForJob`, `getTraceId`, `import`, `enqueueWatch`, `debug`, `enqueueJob`, `createTimestamp`, `checkEntitlement`, `recordUsage`, `createTimestampAndWait`, `waitForJob`, `createBatchTimestamp`, `getJobStatus`, `getStatus`, `getBatchJobStatus`, `getBatchStatus`, `getJobVerification`
|
||||
`createDebugger`, `enqueueWatchForJob`, `getTraceId`, `import`, `enqueueWatch`, `debug`, `enqueueJob`, `createTimestamp`, `checkEntitlement`, `recordUsage`, `createTimestampAndWait`, `waitForJobEvent`, `getStatus`, `waitForJob`, `createBatchTimestamp`, `getJobStatus`, `getBatchJobStatus`, `getBatchStatus`, `getJobVerification`, `lookupHash`
|
||||
|
||||
Each identifier is a call site in this file. Follow the import list to see the defining module; open that module’s MD for parameter and return types.
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
**Package:** `verae-zapier`
|
||||
**Source:** `packages/verae-zapier/index.js`
|
||||
**Lines:** 79
|
||||
**Lines:** 81
|
||||
|
||||
## What this module is
|
||||
|
||||
|
|
@ -32,6 +32,7 @@ _None extracted._
|
|||
- `./creates/batch_timestamp`
|
||||
- `./creates/add_numbers`
|
||||
- `./searches/job_status`
|
||||
- `./searches/hash_lookup`
|
||||
- `./triggers/timestamp_completed`
|
||||
- `zapier-platform-core`
|
||||
- `./package.json`
|
||||
|
|
|
|||
41
docs/modules/verae-zapier/searches/hash_lookup.md
Normal file
41
docs/modules/verae-zapier/searches/hash_lookup.md
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# `verae-zapier/searches/hash_lookup`
|
||||
|
||||
**Package:** `verae-zapier`
|
||||
**Source:** `packages/verae-zapier/searches/hash_lookup.js`
|
||||
**Lines:** 35
|
||||
|
||||
## What this module is
|
||||
|
||||
Implementation module in `verae-zapier`. The tables below are extracted from the source (signatures + JSDoc).
|
||||
|
||||
## Exports
|
||||
|
||||
`key`, `noun`, `display`, `label`, `description`
|
||||
|
||||
## Types / interfaces / classes
|
||||
|
||||
_None extracted._
|
||||
|
||||
## Functions
|
||||
|
||||
| Name | Parameters | Param types (JSDoc) | Returns | Calls (same file / helpers) |
|
||||
|------|------------|---------------------|---------|-----------------------------|
|
||||
| `base` | `(none)` | — | `unknown` | see Call graph |
|
||||
| `perform` | `z, bundle` | — | `unknown` | see Call graph |
|
||||
|
||||
## What it imports / requires
|
||||
|
||||
_No imports detected._
|
||||
|
||||
## Call graph (identifiers invoked)
|
||||
|
||||
`async`, `request`, `base`, `encodeURIComponent`, `digest`
|
||||
|
||||
Each identifier is a call site in this file. Follow the import list to see the defining module; open that module’s MD for parameter and return types.
|
||||
|
||||
## Return values (how to read this)
|
||||
|
||||
- HTTP route handlers return Express `res.json(...)` bodies (see route docs).
|
||||
- Zapier `perform` functions return a **single object** (creates) or an **array** (triggers/searches).
|
||||
- Pricing functions return integer **cents** on `Quote.totalCents`.
|
||||
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
**Package:** `zappier`
|
||||
**Source:** `packages/zappier/src/app.ts`
|
||||
**Lines:** 203
|
||||
**Lines:** 237
|
||||
|
||||
## What this module is
|
||||
|
||||
|
|
@ -47,7 +47,7 @@ Implementation module in `zappier`. The tables below are extracted from the sour
|
|||
|
||||
## Call graph (identifiers invoked)
|
||||
|
||||
`join`, `next`, `parse`, `status`, `json`, `buildApp`, `seeded`, `seedAdminUsersFromEnv`, `rateCard`, `getRateCard`, `tiers`, `getTiers`, `express`, `use`, `load`, `setup`, `adminLoginRouter`, `adminAuth`, `adminRouter`, `static`, `async`, `import`, `toDataURL`, `portalRouter`, `apiKeyAuth`, `middleware`, `get`, `meter`, `post`, `toUpperCase`, `isFinite`, `randomUUID`, `map`, `toISOString`, `unshift`, `filter`, `setUTCDate`, `setUTCHours`, `summaryFor`, `find`, `applyMonthlyCredit`
|
||||
`join`, `next`, `parse`, `status`, `json`, `buildApp`, `seeded`, `seedAdminUsersFromEnv`, `rateCard`, `getRateCard`, `tiers`, `getTiers`, `express`, `use`, `load`, `setup`, `adminLoginRouter`, `adminAuth`, `adminRouter`, `static`, `async`, `import`, `toDataURL`, `portalRouter`, `apiKeyAuth`, `middleware`, `get`, `meter`, `post`, `toUpperCase`, `toLowerCase`, `createHash`, `update`, `digest`, `randomUUID`, `toISOString`, `set`, `isFinite`, `map`, `unshift`, `filter`, `setUTCDate`, `setUTCHours`, `summaryFor`, `find`, `applyMonthlyCredit`
|
||||
|
||||
Each identifier is a call site in this file. Follow the import list to see the defining module; open that module’s MD for parameter and return types.
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
**Package:** `zappier`
|
||||
**Source:** `packages/zappier/src/pricing.ts`
|
||||
**Lines:** 171
|
||||
**Lines:** 173
|
||||
|
||||
## What this module is
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,6 @@
|
|||
Verae × Zapier module reference
|
||||
=================================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Models
|
||||
|
||||
models/PriceRule
|
||||
models/TierConfig
|
||||
models/RateCard
|
||||
models/Quote
|
||||
models/CallUsage
|
||||
models/Customer
|
||||
models/AddNumbersResult
|
||||
models/TimestampRequest
|
||||
models/TimestampResponse
|
||||
models/StatusResponse
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Modules
|
||||
|
|
@ -61,7 +46,9 @@ Verae × Zapier module reference
|
|||
modules/verae-zapier-middleware/nats/connection
|
||||
modules/verae-zapier-middleware/nats/publishers
|
||||
modules/verae-zapier-middleware/nats/subjects
|
||||
modules/verae-zapier-middleware/nats/wait
|
||||
modules/verae-zapier-middleware/routes/authRoutes
|
||||
modules/verae-zapier-middleware/routes/hashRoutes
|
||||
modules/verae-zapier-middleware/routes/index
|
||||
modules/verae-zapier-middleware/routes/statusRoutes
|
||||
modules/verae-zapier-middleware/routes/tenantRoutes
|
||||
|
|
@ -84,6 +71,7 @@ Verae × Zapier module reference
|
|||
modules/verae-zapier-middleware/workers/webhookWorker
|
||||
modules/verae-activate/authentication
|
||||
modules/verae-activate/creates/add_numbers
|
||||
modules/verae-activate/creates/echo
|
||||
modules/verae-activate/index
|
||||
modules/verae-zapier/authentication
|
||||
modules/verae-zapier/creates/add_numbers
|
||||
|
|
@ -92,5 +80,6 @@ Verae × Zapier module reference
|
|||
modules/verae-zapier/creates/timestamp_and_wait
|
||||
modules/verae-zapier/creates/verify_timestamp
|
||||
modules/verae-zapier/index
|
||||
modules/verae-zapier/searches/hash_lookup
|
||||
modules/verae-zapier/searches/job_status
|
||||
modules/verae-zapier/triggers/timestamp_completed
|
||||
|
|
|
|||
40
docs/sphinx/modules/verae-activate/creates/echo.md
Normal file
40
docs/sphinx/modules/verae-activate/creates/echo.md
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# `verae-activate/creates/echo`
|
||||
|
||||
**Package:** `verae-activate`
|
||||
**Source:** `packages/verae-activate/creates/echo.js`
|
||||
**Lines:** 30
|
||||
|
||||
## What this module is
|
||||
|
||||
Implementation module in `verae-activate`. The tables below are extracted from the source (signatures + JSDoc).
|
||||
|
||||
## Exports
|
||||
|
||||
`key`, `noun`, `display`, `label`, `description`
|
||||
|
||||
## Types / interfaces / classes
|
||||
|
||||
_None extracted._
|
||||
|
||||
## Functions
|
||||
|
||||
| Name | Parameters | Param types (JSDoc) | Returns | Calls (same file / helpers) |
|
||||
|------|------------|---------------------|---------|-----------------------------|
|
||||
| `perform` | `_z, bundle` | — | `unknown` | see Call graph |
|
||||
|
||||
## What it imports / requires
|
||||
|
||||
_No imports detected._
|
||||
|
||||
## Call graph (identifiers invoked)
|
||||
|
||||
`action`, `async`
|
||||
|
||||
Each identifier is a call site in this file. Follow the import list to see the defining module; open that module’s MD for parameter and return types.
|
||||
|
||||
## Return values (how to read this)
|
||||
|
||||
- HTTP route handlers return Express `res.json(...)` bodies (see route docs).
|
||||
- Zapier `perform` functions return a **single object** (creates) or an **array** (triggers/searches).
|
||||
- Pricing functions return integer **cents** on `Quote.totalCents`.
|
||||
|
||||
7
docs/sphinx/modules/verae-activate/creates/echo.rst
Normal file
7
docs/sphinx/modules/verae-activate/creates/echo.rst
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
verae-activate.creates.echo
|
||||
===========================
|
||||
|
||||
Generated API sheet for ``verae-activate/creates/echo``.
|
||||
|
||||
.. include:: echo.md
|
||||
:literal:
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
**Package:** `verae-activate`
|
||||
**Source:** `packages/verae-activate/index.js`
|
||||
**Lines:** 21
|
||||
**Lines:** 23
|
||||
|
||||
## What this module is
|
||||
|
||||
|
|
@ -10,7 +10,7 @@ Implementation module in `verae-activate`. The tables below are extracted from t
|
|||
|
||||
## Exports
|
||||
|
||||
`version`, `platformVersion`, `authentication`, `creates`, `addNumbers`
|
||||
`version`, `platformVersion`, `authentication`, `creates`, `addNumbers`, `echo`
|
||||
|
||||
## Types / interfaces / classes
|
||||
|
||||
|
|
@ -24,6 +24,7 @@ _No top-level functions extracted._
|
|||
|
||||
- `./authentication`
|
||||
- `./creates/add_numbers`
|
||||
- `./creates/echo`
|
||||
- `./package.json`
|
||||
- `zapier-platform-core`
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
**Package:** `verae-zapier-middleware`
|
||||
**Source:** `packages/verae-zapier-middleware/src/clients/veraeClient.js`
|
||||
**Lines:** 288
|
||||
**Lines:** 351
|
||||
|
||||
## What this module is
|
||||
|
||||
|
|
@ -10,7 +10,7 @@ Implementation module in `verae-zapier-middleware`. The tables below are extract
|
|||
|
||||
## Exports
|
||||
|
||||
`veraeClient`, `clearMockJobs`
|
||||
`sha256Hex`, `veraeClient`, `clearMockJobs`
|
||||
|
||||
## Types / interfaces / classes
|
||||
|
||||
|
|
@ -20,11 +20,13 @@ _None extracted._
|
|||
|
||||
| Name | Parameters | Param types (JSDoc) | Returns | Calls (same file / helpers) |
|
||||
|------|------------|---------------------|---------|-----------------------------|
|
||||
| `sha256Hex` | `data` | data: `string` | `string` | see Call graph |
|
||||
| `delay` | `ms` | ms: `number` | `Promise<void>` | see Call graph |
|
||||
| `mockLogin` | `{ username, password }` | ms: `number` | `Promise<void>` | see Call graph |
|
||||
| `mockValidate` | `token` | — | `unknown` | see Call graph |
|
||||
| `mockCreateTimestamp` | `{ data, hashAlg }` | — | `unknown` | see Call graph |
|
||||
| `mockCreateTimestamp` | `{ data, hashAlg, sha256, publicMetadata, privateMetadata }` | — | `unknown` | see Call graph |
|
||||
| `mockGetStatus` | `jobId` | — | `unknown` | see Call graph |
|
||||
| `mockLookupHash` | `sha256` | — | `unknown` | see Call graph |
|
||||
| `mockVerify` | `{ certificate }` | — | `unknown` | see Call graph |
|
||||
| `request` | `path, { method = 'GET', token, body } = {}` | path: `string` | `Promise<any>` | see Call graph |
|
||||
| `clearMockJobs` | `(none)` | — | `void` | see Call graph |
|
||||
|
|
@ -37,6 +39,7 @@ _None extracted._
|
|||
| `login` | `credentials` |
|
||||
| `validate` | `token` |
|
||||
| `createTimestamp` | `token, body` |
|
||||
| `lookupHash` | `token, sha256` |
|
||||
| `createBatchTimestamp` | `token, body` |
|
||||
| `getStatus` | `token, jobId` |
|
||||
| `getBatchStatus` | `token, body` |
|
||||
|
|
@ -54,7 +57,7 @@ _None extracted._
|
|||
|
||||
## Call graph (identifiers invoked)
|
||||
|
||||
`net`, `createDebugger`, `delay`, `setTimeout`, `mockLogin`, `now`, `toISOString`, `randomUUID`, `includes`, `mockValidate`, `startsWith`, `replace`, `mockCreateTimestamp`, `set`, `get`, `mockGetStatus`, `mockVerify`, `request`, `debug`, `fetch`, `stringify`, `text`, `parse`, `error`, `client`, `login`, `validate`, `createTimestamp`, `createBatchTimestamp`, `push`, `getStatus`, `encodeURIComponent`, `getBatchStatus`, `verify`, `verifyBatch`, `getJobVerification`, `waitForJob`, `jobs`, `clearMockJobs`, `clear`
|
||||
`net`, `createDebugger`, `sha256Hex`, `createHash`, `update`, `digest`, `delay`, `setTimeout`, `mockLogin`, `now`, `toISOString`, `randomUUID`, `includes`, `mockValidate`, `startsWith`, `replace`, `mockCreateTimestamp`, `toLowerCase`, `get`, `set`, `mockGetStatus`, `mockLookupHash`, `mockVerify`, `request`, `debug`, `fetch`, `stringify`, `text`, `parse`, `error`, `client`, `login`, `validate`, `createTimestamp`, `lookupHash`, `createBatchTimestamp`, `push`, `getStatus`, `encodeURIComponent`, `getBatchStatus`, `verify`, `verifyBatch`, `getJobVerification`, `waitForJob`, `jobs`, `clearMockJobs`, `clear`
|
||||
|
||||
Each identifier is a call site in this file. Follow the import list to see the defining module; open that module’s MD for parameter and return types.
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
**Package:** `verae-zapier-middleware`
|
||||
**Source:** `packages/verae-zapier-middleware/src/config.js`
|
||||
**Lines:** 143
|
||||
**Lines:** 145
|
||||
|
||||
## What this module is
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
**Package:** `verae-zapier-middleware`
|
||||
**Source:** `packages/verae-zapier-middleware/src/nats/connection.js`
|
||||
**Lines:** 112
|
||||
**Lines:** 117
|
||||
|
||||
## What this module is
|
||||
|
||||
|
|
@ -10,7 +10,7 @@ Implementation module in `verae-zapier-middleware`. The tables below are extract
|
|||
|
||||
## Exports
|
||||
|
||||
`connectNats`, `ensureStreams`, `closeNats`, `getJetStream`, `isNatsConnected`
|
||||
`connectNats`, `getNatsConnection`, `ensureStreams`, `closeNats`, `getJetStream`, `isNatsConnected`
|
||||
|
||||
## Types / interfaces / classes
|
||||
|
||||
|
|
@ -21,6 +21,7 @@ _None extracted._
|
|||
| Name | Parameters | Param types (JSDoc) | Returns | Calls (same file / helpers) |
|
||||
|------|------------|---------------------|---------|-----------------------------|
|
||||
| `connectNats` | `url = config.natsUrl` | url: `string` | `Promise<{ nc: import('nats').NatsConnection, js: import('nats').JetStreamClient, jsm: import('nats').JetStreamManager ` — >} | see Call graph |
|
||||
| `getNatsConnection` | `(none)` | — | `import('nats').NatsConnection|null` | see Call graph |
|
||||
| `ensureStreams` | `manager` | manager: `import('nats').JetStreamManager` | `Promise<void>` | see Call graph |
|
||||
| `closeNats` | `(none)` | — | `Promise<void>` | see Call graph |
|
||||
| `getJetStream` | `(none)` | — | `import('nats').JetStreamClient|null` | see Call graph |
|
||||
|
|
@ -34,7 +35,7 @@ _None extracted._
|
|||
|
||||
## Call graph (identifiers invoked)
|
||||
|
||||
`createDebugger`, `import`, `connectNats`, `debug`, `disabled`, `info`, `connect`, `jetstream`, `jetstreamManager`, `ensureStreams`, `add`, `closeNats`, `drain`, `getJetStream`, `isNatsConnected`, `isClosed`
|
||||
`createDebugger`, `import`, `connectNats`, `debug`, `disabled`, `info`, `connect`, `jetstream`, `jetstreamManager`, `getNatsConnection`, `ensureStreams`, `add`, `closeNats`, `drain`, `getJetStream`, `isNatsConnected`, `isClosed`
|
||||
|
||||
Each identifier is a call site in this file. Follow the import list to see the defining module; open that module’s MD for parameter and return types.
|
||||
|
||||
|
|
|
|||
44
docs/sphinx/modules/verae-zapier-middleware/nats/wait.md
Normal file
44
docs/sphinx/modules/verae-zapier-middleware/nats/wait.md
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
# `verae-zapier-middleware/nats/wait`
|
||||
|
||||
**Package:** `verae-zapier-middleware`
|
||||
**Source:** `packages/verae-zapier-middleware/src/nats/wait.js`
|
||||
**Lines:** 60
|
||||
|
||||
## What this module is
|
||||
|
||||
Implementation module in `verae-zapier-middleware`. The tables below are extracted from the source (signatures + JSDoc).
|
||||
|
||||
## Exports
|
||||
|
||||
`waitForJobEvent`
|
||||
|
||||
## Types / interfaces / classes
|
||||
|
||||
_None extracted._
|
||||
|
||||
## Functions
|
||||
|
||||
| Name | Parameters | Param types (JSDoc) | Returns | Calls (same file / helpers) |
|
||||
|------|------------|---------------------|---------|-----------------------------|
|
||||
| `waitForJobEvent` | `jobId, timeoutMs` | jobId: `string`, timeoutMs: `number` | `Promise<object|null>` — event payload or null on timeout | see Call graph |
|
||||
| `firstMatch` | `async (` | — | `unknown` | see Call graph |
|
||||
|
||||
## What it imports / requires
|
||||
|
||||
- `../debug/logger.js`
|
||||
- `../debug/trace-context.js`
|
||||
- `./subjects.js`
|
||||
- `./connection.js`
|
||||
|
||||
## Call graph (identifiers invoked)
|
||||
|
||||
`createDebugger`, `waitForJobEvent`, `getNatsConnection`, `connectNats`, `subscribe`, `getTraceId`, `debug`, `setTimeout`, `resolve`, `async`, `parse`, `string`, `race`, `unsubscribe`
|
||||
|
||||
Each identifier is a call site in this file. Follow the import list to see the defining module; open that module’s MD for parameter and return types.
|
||||
|
||||
## Return values (how to read this)
|
||||
|
||||
- HTTP route handlers return Express `res.json(...)` bodies (see route docs).
|
||||
- Zapier `perform` functions return a **single object** (creates) or an **array** (triggers/searches).
|
||||
- Pricing functions return integer **cents** on `Quote.totalCents`.
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
verae-zapier-middleware.nats.wait
|
||||
=================================
|
||||
|
||||
Generated API sheet for ``verae-zapier-middleware/nats/wait``.
|
||||
|
||||
.. include:: wait.md
|
||||
:literal:
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
# `verae-zapier-middleware/routes/hashRoutes`
|
||||
|
||||
**Package:** `verae-zapier-middleware`
|
||||
**Source:** `packages/verae-zapier-middleware/src/routes/hashRoutes.js`
|
||||
**Lines:** 22
|
||||
|
||||
## What this module is
|
||||
|
||||
Implementation module in `verae-zapier-middleware`. The tables below are extracted from the source (signatures + JSDoc).
|
||||
|
||||
## Exports
|
||||
|
||||
`hashRoutes`
|
||||
|
||||
## Types / interfaces / classes
|
||||
|
||||
_None extracted._
|
||||
|
||||
## Functions
|
||||
|
||||
_No top-level functions extracted._
|
||||
|
||||
## Methods (class / object)
|
||||
|
||||
| Name | Parameters |
|
||||
|------|------------|
|
||||
| `asyncHandler` | `async (req, res` |
|
||||
|
||||
## What it imports / requires
|
||||
|
||||
- `express`
|
||||
- `../errors.js`
|
||||
- `../services/timestampService.js`
|
||||
|
||||
## Call graph (identifiers invoked)
|
||||
|
||||
`get`, `asyncHandler`, `async`, `test`, `lookupHash`, `json`
|
||||
|
||||
Each identifier is a call site in this file. Follow the import list to see the defining module; open that module’s MD for parameter and return types.
|
||||
|
||||
## Return values (how to read this)
|
||||
|
||||
- HTTP route handlers return Express `res.json(...)` bodies (see route docs).
|
||||
- Zapier `perform` functions return a **single object** (creates) or an **array** (triggers/searches).
|
||||
- Pricing functions return integer **cents** on `Quote.totalCents`.
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
verae-zapier-middleware.routes.hashRoutes
|
||||
=========================================
|
||||
|
||||
Generated API sheet for ``verae-zapier-middleware/routes/hashRoutes``.
|
||||
|
||||
.. include:: hashRoutes.md
|
||||
:literal:
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
**Package:** `verae-zapier-middleware`
|
||||
**Source:** `packages/verae-zapier-middleware/src/routes/index.js`
|
||||
**Lines:** 34
|
||||
**Lines:** 36
|
||||
|
||||
## What this module is
|
||||
|
||||
|
|
@ -29,6 +29,7 @@ _No top-level functions extracted._
|
|||
- `./statusRoutes.js`
|
||||
- `./webhookRoutes.js`
|
||||
- `./tenantRoutes.js`
|
||||
- `./hashRoutes.js`
|
||||
- `../middleware/authenticate.js`
|
||||
- `../middleware/rateLimit.js`
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
**Package:** `verae-zapier-middleware`
|
||||
**Source:** `packages/verae-zapier-middleware/src/routes/timestampRoutes.js`
|
||||
**Lines:** 50
|
||||
**Lines:** 62
|
||||
|
||||
## What this module is
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
**Package:** `verae-zapier-middleware`
|
||||
**Source:** `packages/verae-zapier-middleware/src/services/timestampService.js`
|
||||
**Lines:** 123
|
||||
**Lines:** 160
|
||||
|
||||
## What this module is
|
||||
|
||||
|
|
@ -10,7 +10,7 @@ Implementation module in `verae-zapier-middleware`. The tables below are extract
|
|||
|
||||
## Exports
|
||||
|
||||
`createTimestamp`, `createTimestampAndWait`, `createBatchTimestamp`, `getJobStatus`, `getBatchJobStatus`, `getJobVerification`
|
||||
`createTimestamp`, `createTimestampAndWait`, `createBatchTimestamp`, `getJobStatus`, `getBatchJobStatus`, `getJobVerification`, `lookupHash`
|
||||
|
||||
## Types / interfaces / classes
|
||||
|
||||
|
|
@ -21,12 +21,13 @@ _None extracted._
|
|||
| Name | Parameters | Param types (JSDoc) | Returns | Calls (same file / helpers) |
|
||||
|------|------------|---------------------|---------|-----------------------------|
|
||||
| `enqueueWatchForJob` | `ctx, jobId` | ctx: `object`, jobId: `string` | `unknown` | see Call graph |
|
||||
| `createTimestamp` | `ctx, body` | ctx: `object` | `Promise<{ jobId: string ` — >} | see Call graph |
|
||||
| `createTimestamp` | `ctx, body` | ctx: `object` | `Promise<{ jobId: string, sha256?: string, existing?: boolean ` — >} | see Call graph |
|
||||
| `createTimestampAndWait` | `ctx, body` | ctx: `object` | `Promise<object>` — StatusResponse | see Call graph |
|
||||
| `createBatchTimestamp` | `ctx, body` | ctx: `object` | `unknown` | see Call graph |
|
||||
| `getJobStatus` | `ctx, jobId` | ctx: `object`, jobId: `string` | `unknown` | see Call graph |
|
||||
| `getBatchJobStatus` | `ctx, body` | ctx: `object` | `unknown` | see Call graph |
|
||||
| `getJobVerification` | `ctx, jobId` | ctx: `object`, jobId: `string` | `unknown` | see Call graph |
|
||||
| `lookupHash` | `ctx, sha256` | ctx: `object`, sha256: `string` | `unknown` | see Call graph |
|
||||
|
||||
## Methods (class / object)
|
||||
|
||||
|
|
@ -40,12 +41,12 @@ _None extracted._
|
|||
}` |
|
||||
| `checkEntitlement` | `ctx.tenantId, 'timestamp'` |
|
||||
| `recordUsage` | `ctx.tenantId, 'timestamp'` |
|
||||
| `recordUsage` | `ctx.tenantId, 'status'` |
|
||||
| `checkEntitlement` | `ctx.tenantId, 'batch_timestamp', { amount: itemCount }` |
|
||||
| `recordUsage` | `ctx.tenantId, 'batch_timestamp', { amount: itemCount }` |
|
||||
| `recordUsage` | `ctx.tenantId, 'status'` |
|
||||
| `recordUsage` | `ctx.tenantId, 'status', { amount: body.jobIds?.length ?? 1 }` |
|
||||
| `recordUsage` | `ctx.tenantId, 'status'` |
|
||||
| `recordUsage` | `ctx.tenantId, 'status'` |
|
||||
|
||||
## What it imports / requires
|
||||
|
||||
|
|
@ -58,7 +59,7 @@ _None extracted._
|
|||
|
||||
## Call graph (identifiers invoked)
|
||||
|
||||
`createDebugger`, `enqueueWatchForJob`, `getTraceId`, `import`, `enqueueWatch`, `debug`, `enqueueJob`, `createTimestamp`, `checkEntitlement`, `recordUsage`, `createTimestampAndWait`, `waitForJob`, `createBatchTimestamp`, `getJobStatus`, `getStatus`, `getBatchJobStatus`, `getBatchStatus`, `getJobVerification`
|
||||
`createDebugger`, `enqueueWatchForJob`, `getTraceId`, `import`, `enqueueWatch`, `debug`, `enqueueJob`, `createTimestamp`, `checkEntitlement`, `recordUsage`, `createTimestampAndWait`, `waitForJobEvent`, `getStatus`, `waitForJob`, `createBatchTimestamp`, `getJobStatus`, `getBatchJobStatus`, `getBatchStatus`, `getJobVerification`, `lookupHash`
|
||||
|
||||
Each identifier is a call site in this file. Follow the import list to see the defining module; open that module’s MD for parameter and return types.
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
**Package:** `verae-zapier`
|
||||
**Source:** `packages/verae-zapier/index.js`
|
||||
**Lines:** 79
|
||||
**Lines:** 81
|
||||
|
||||
## What this module is
|
||||
|
||||
|
|
@ -32,6 +32,7 @@ _None extracted._
|
|||
- `./creates/batch_timestamp`
|
||||
- `./creates/add_numbers`
|
||||
- `./searches/job_status`
|
||||
- `./searches/hash_lookup`
|
||||
- `./triggers/timestamp_completed`
|
||||
- `zapier-platform-core`
|
||||
- `./package.json`
|
||||
|
|
|
|||
41
docs/sphinx/modules/verae-zapier/searches/hash_lookup.md
Normal file
41
docs/sphinx/modules/verae-zapier/searches/hash_lookup.md
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# `verae-zapier/searches/hash_lookup`
|
||||
|
||||
**Package:** `verae-zapier`
|
||||
**Source:** `packages/verae-zapier/searches/hash_lookup.js`
|
||||
**Lines:** 35
|
||||
|
||||
## What this module is
|
||||
|
||||
Implementation module in `verae-zapier`. The tables below are extracted from the source (signatures + JSDoc).
|
||||
|
||||
## Exports
|
||||
|
||||
`key`, `noun`, `display`, `label`, `description`
|
||||
|
||||
## Types / interfaces / classes
|
||||
|
||||
_None extracted._
|
||||
|
||||
## Functions
|
||||
|
||||
| Name | Parameters | Param types (JSDoc) | Returns | Calls (same file / helpers) |
|
||||
|------|------------|---------------------|---------|-----------------------------|
|
||||
| `base` | `(none)` | — | `unknown` | see Call graph |
|
||||
| `perform` | `z, bundle` | — | `unknown` | see Call graph |
|
||||
|
||||
## What it imports / requires
|
||||
|
||||
_No imports detected._
|
||||
|
||||
## Call graph (identifiers invoked)
|
||||
|
||||
`async`, `request`, `base`, `encodeURIComponent`, `digest`
|
||||
|
||||
Each identifier is a call site in this file. Follow the import list to see the defining module; open that module’s MD for parameter and return types.
|
||||
|
||||
## Return values (how to read this)
|
||||
|
||||
- HTTP route handlers return Express `res.json(...)` bodies (see route docs).
|
||||
- Zapier `perform` functions return a **single object** (creates) or an **array** (triggers/searches).
|
||||
- Pricing functions return integer **cents** on `Quote.totalCents`.
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
verae-zapier.searches.hash_lookup
|
||||
=================================
|
||||
|
||||
Generated API sheet for ``verae-zapier/searches/hash_lookup``.
|
||||
|
||||
.. include:: hash_lookup.md
|
||||
:literal:
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
**Package:** `zappier`
|
||||
**Source:** `packages/zappier/src/app.ts`
|
||||
**Lines:** 203
|
||||
**Lines:** 237
|
||||
|
||||
## What this module is
|
||||
|
||||
|
|
@ -47,7 +47,7 @@ Implementation module in `zappier`. The tables below are extracted from the sour
|
|||
|
||||
## Call graph (identifiers invoked)
|
||||
|
||||
`join`, `next`, `parse`, `status`, `json`, `buildApp`, `seeded`, `seedAdminUsersFromEnv`, `rateCard`, `getRateCard`, `tiers`, `getTiers`, `express`, `use`, `load`, `setup`, `adminLoginRouter`, `adminAuth`, `adminRouter`, `static`, `async`, `import`, `toDataURL`, `portalRouter`, `apiKeyAuth`, `middleware`, `get`, `meter`, `post`, `toUpperCase`, `isFinite`, `randomUUID`, `map`, `toISOString`, `unshift`, `filter`, `setUTCDate`, `setUTCHours`, `summaryFor`, `find`, `applyMonthlyCredit`
|
||||
`join`, `next`, `parse`, `status`, `json`, `buildApp`, `seeded`, `seedAdminUsersFromEnv`, `rateCard`, `getRateCard`, `tiers`, `getTiers`, `express`, `use`, `load`, `setup`, `adminLoginRouter`, `adminAuth`, `adminRouter`, `static`, `async`, `import`, `toDataURL`, `portalRouter`, `apiKeyAuth`, `middleware`, `get`, `meter`, `post`, `toUpperCase`, `toLowerCase`, `createHash`, `update`, `digest`, `randomUUID`, `toISOString`, `set`, `isFinite`, `map`, `unshift`, `filter`, `setUTCDate`, `setUTCHours`, `summaryFor`, `find`, `applyMonthlyCredit`
|
||||
|
||||
Each identifier is a call site in this file. Follow the import list to see the defining module; open that module’s MD for parameter and return types.
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
**Package:** `zappier`
|
||||
**Source:** `packages/zappier/src/pricing.ts`
|
||||
**Lines:** 171
|
||||
**Lines:** 173
|
||||
|
||||
## What this module is
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,49 @@
|
|||
#!/usr/bin/env bash
|
||||
# Disconnected smoke (expand in PR 3 / PR 4).
|
||||
# GATE 12 — disconnected E2E: middleware health, signup, timestamp, wait (NATS off).
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
echo "workspace: $ROOT"
|
||||
curl -fsS "http://127.0.0.1:3100/health" || {
|
||||
echo "middleware /health not up — start packages/verae-zapier-middleware with MOCK_VERAE=true"
|
||||
exit 1
|
||||
export MOCK_VERAE=true
|
||||
export NATS_ENABLED=false
|
||||
export PORT="${PORT:-3100}"
|
||||
export TOKEN_SECRET=dev-secret
|
||||
cd "$ROOT/packages/verae-zapier-middleware"
|
||||
|
||||
started=0
|
||||
if ! curl -fsS "http://127.0.0.1:${PORT}/health" >/dev/null 2>&1; then
|
||||
node src/index.js >/tmp/verae-mw-smoke.log 2>&1 &
|
||||
started=$!
|
||||
for i in $(seq 1 40); do
|
||||
if curl -fsS "http://127.0.0.1:${PORT}/health" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 0.15
|
||||
done
|
||||
fi
|
||||
|
||||
cleanup() {
|
||||
if [[ "$started" != "0" ]]; then
|
||||
kill "$started" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
echo "middleware health ok"
|
||||
trap cleanup EXIT
|
||||
|
||||
curl -fsS "http://127.0.0.1:${PORT}/health" | grep -q ok
|
||||
echo "health ok"
|
||||
|
||||
signup=$(curl -fsS -X POST "http://127.0.0.1:${PORT}/zapier/v1/signup" \
|
||||
-H 'content-type: application/json' \
|
||||
-d '{"email":"smoke@example.com","name":"smoke","veraeUsername":"smokeuser","veraePassword":"smokepass"}')
|
||||
key=$(node -e "const j=JSON.parse(process.argv[1]); process.stdout.write(j.apiKey||'')" "$signup")
|
||||
if [[ -z "$key" ]]; then
|
||||
echo "signup did not return apiKey: $signup" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "signup ok"
|
||||
|
||||
wait=$(curl -fsS -X POST "http://127.0.0.1:${PORT}/zapier/v1/timestamp/wait" \
|
||||
-H "authorization: Bearer $key" \
|
||||
-H 'content-type: application/json' \
|
||||
-d '{"data":"smoke-payload"}')
|
||||
echo "$wait" | grep -q completed
|
||||
echo "timestamp wait ok"
|
||||
echo "GATE 12 PASSED"
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@
|
|||
"gate:6": "npm --prefix packages/verae-zapier-middleware run test:gate6",
|
||||
"gate:7": "npm --prefix packages/verae-zapier-middleware run test:gate7",
|
||||
"gate:8": "npm --prefix packages/verae-zapier-middleware run test:gate8",
|
||||
"gate:9": "node scripts/gate-not-ready.mjs 9",
|
||||
"gate:9": "npm --prefix packages/verae-zapier-middleware run test:gate9",
|
||||
"gate:10": "npm --prefix packages/verae-zapier-middleware run test:gate10",
|
||||
"gate:11": "node --test packages/verae-zapier/test/app.test.js",
|
||||
"gate:12": "node scripts/gate-not-ready.mjs 12",
|
||||
"gate:12": "bash harness/scripts/smoke.sh",
|
||||
"gate:13": "node scripts/gate-not-ready.mjs 13",
|
||||
"gate:all": "node scripts/gate-all.mjs",
|
||||
"test:middleware": "npm --prefix packages/verae-zapier-middleware test",
|
||||
|
|
|
|||
29
packages/verae-activate/creates/echo.js
Normal file
29
packages/verae-activate/creates/echo.js
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* Echo — returns the input string. Second activate-now action (no backend).
|
||||
* @module creates/echo
|
||||
*/
|
||||
|
||||
const perform = async (_z, bundle) => {
|
||||
const text = String(bundle.inputData.text ?? '');
|
||||
return { text, length: text.length, mode: 'local' };
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
key: 'echo',
|
||||
noun: 'Echo',
|
||||
display: {
|
||||
label: 'Echo Text',
|
||||
description: 'Returns the text you send. No API required.',
|
||||
},
|
||||
operation: {
|
||||
cleanInputData: false,
|
||||
inputFields: [{ key: 'text', label: 'Text', type: 'string', required: true }],
|
||||
perform,
|
||||
sample: { text: 'hello', length: 5, mode: 'local' },
|
||||
outputFields: [
|
||||
{ key: 'text', type: 'string' },
|
||||
{ key: 'length', type: 'integer' },
|
||||
{ key: 'mode', type: 'string' },
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
const authentication = require('./authentication');
|
||||
const addNumbers = require('./creates/add_numbers');
|
||||
const echo = require('./creates/echo');
|
||||
|
||||
module.exports = {
|
||||
version: require('./package.json').version,
|
||||
|
|
@ -16,5 +17,6 @@ module.exports = {
|
|||
authentication,
|
||||
creates: {
|
||||
[addNumbers.key]: addNumbers,
|
||||
[echo.key]: echo,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ describe('verae-activate app', () => {
|
|||
it('exports Add Numbers create and custom auth', () => {
|
||||
assert.equal(authentication.type, 'custom');
|
||||
assert.ok(App.creates.add_numbers);
|
||||
assert.ok(App.creates.echo);
|
||||
assert.equal(addNumbers.key, 'add_numbers');
|
||||
assert.ok(addNumbers.operation.inputFields.some((f) => f.key === 'number1'));
|
||||
assert.ok(addNumbers.operation.inputFields.some((f) => f.key === 'number2'));
|
||||
|
|
@ -63,6 +64,13 @@ describe('verae-activate app', () => {
|
|||
assert.equal(result.sum, 5);
|
||||
});
|
||||
|
||||
it('echo returns text length', async () => {
|
||||
const echo = require('../creates/echo');
|
||||
const out = await echo.operation.perform({}, { inputData: { text: 'ab' }, authData: {} });
|
||||
assert.equal(out.length, 2);
|
||||
assert.equal(out.mode, 'local');
|
||||
});
|
||||
|
||||
it('auth test is local when fields empty', async () => {
|
||||
const out = await authentication.test({ request: async () => ({ data: {} }) }, { authData: {} });
|
||||
assert.equal(out.ok, true);
|
||||
|
|
|
|||
|
|
@ -7,8 +7,13 @@ VERAE_API_BASE_URL=https://api.veraetime.net
|
|||
MOCK_VERAE=false
|
||||
|
||||
# NATS (Phase 7+)
|
||||
# NS1 JetStream is 127.0.0.1:4222 on 70.88.205.138 (not public).
|
||||
# Tunnel: ssh -fN -L 14222:127.0.0.1:4222 marchon@70.88.205.138
|
||||
# then NATS_URL=nats://127.0.0.1:14222
|
||||
NATS_ENABLED=false
|
||||
NATS_URL=nats://127.0.0.1:4222
|
||||
WAIT_TIMEOUT_MS=25000
|
||||
MOCK_JOB_COMPLETE_MS=150
|
||||
|
||||
# Security
|
||||
TOKEN_SECRET=change-me-in-production
|
||||
|
|
|
|||
|
|
@ -17,7 +17,9 @@
|
|||
"test:gate6": "MOCK_VERAE=true NATS_ENABLED=false JOB_POLL_INTERVAL_MS=20 JOB_POLL_MAX_ATTEMPTS=50 node --test test/integration/http-api.test.js",
|
||||
"test:gate7": "MOCK_VERAE=true NATS_ENABLED=true NATS_FORCE_CONNECT=1 NATS_URL=nats://127.0.0.1:4222 node --test test/integration/nats.test.js",
|
||||
"test:gate8": "MOCK_VERAE=true NATS_ENABLED=true NATS_FORCE_CONNECT=1 NATS_URL=nats://127.0.0.1:4222 JOB_POLL_INTERVAL_MS=50 node --test test/integration/nats-workers.test.js",
|
||||
"test:gate10": "MOCK_VERAE=true NATS_ENABLED=false node --test test/integration/tenants.test.js"
|
||||
"test:gate9": "MOCK_VERAE=true NATS_ENABLED=true NATS_FORCE_CONNECT=1 NATS_URL=nats://127.0.0.1:4222 JOB_POLL_INTERVAL_MS=40 WAIT_TIMEOUT_MS=8000 node --test test/integration/wait-nats.test.js",
|
||||
"test:gate10": "MOCK_VERAE=true NATS_ENABLED=false node --test test/integration/tenants.test.js",
|
||||
"test:hash": "MOCK_VERAE=true NATS_ENABLED=false node --test test/integration/hash.test.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.0.0"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* @module clients/veraeClient
|
||||
*/
|
||||
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import { createHash, randomUUID } from 'node:crypto';
|
||||
import { config } from '../config.js';
|
||||
import { AppError } from '../errors.js';
|
||||
import { createDebugger } from '../debug/logger.js';
|
||||
|
|
@ -11,6 +11,16 @@ import { createDebugger } from '../debug/logger.js';
|
|||
const log = createDebugger('http');
|
||||
|
||||
const mockJobs = new Map();
|
||||
/** @type {Map<string, { jobId: string, sha256: string, timestamp?: string, publicMetadata?: object, privateMetadata?: object }>} */
|
||||
const mockHashes = new Map();
|
||||
|
||||
/**
|
||||
* @param {string} data
|
||||
* @returns {string}
|
||||
*/
|
||||
export function sha256Hex(data) {
|
||||
return createHash('sha256').update(String(data), 'utf8').digest('hex');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} ms
|
||||
|
|
@ -50,19 +60,36 @@ async function mockValidate(token) {
|
|||
};
|
||||
}
|
||||
|
||||
async function mockCreateTimestamp({ data, hashAlg }) {
|
||||
if (!data) {
|
||||
async function mockCreateTimestamp({ data, hashAlg, sha256, publicMetadata, privateMetadata }) {
|
||||
if (!data && !sha256) {
|
||||
throw new AppError('Invalid input data', { status: 400, code: 'VALIDATION_ERROR' });
|
||||
}
|
||||
const key = (sha256 || sha256Hex(data)).toLowerCase();
|
||||
const existing = mockHashes.get(key);
|
||||
if (existing) {
|
||||
const job = mockJobs.get(existing.jobId);
|
||||
return {
|
||||
jobId: existing.jobId,
|
||||
sha256: key,
|
||||
existing: true,
|
||||
timestamp: job?.completedAt ?? existing.timestamp,
|
||||
};
|
||||
}
|
||||
|
||||
const jobId = randomUUID();
|
||||
mockJobs.set(jobId, {
|
||||
id: jobId,
|
||||
status: 'pending',
|
||||
createdAt: Date.now(),
|
||||
data,
|
||||
data: data ?? key,
|
||||
hashAlg: hashAlg ?? 'SHA256',
|
||||
sha256: key,
|
||||
publicMetadata: publicMetadata ?? {},
|
||||
privateMetadata: privateMetadata ?? {},
|
||||
});
|
||||
mockHashes.set(key, { jobId, sha256: key, publicMetadata, privateMetadata });
|
||||
|
||||
const delayMs = config.mockJobCompleteMs ?? 150;
|
||||
setTimeout(() => {
|
||||
const job = mockJobs.get(jobId);
|
||||
if (!job) return;
|
||||
|
|
@ -73,10 +100,14 @@ async function mockCreateTimestamp({ data, hashAlg }) {
|
|||
blockIndex: 42,
|
||||
timestamp: job.completedAt,
|
||||
certificate: job.result,
|
||||
sha256: key,
|
||||
publicMetadata: job.publicMetadata,
|
||||
};
|
||||
}, 150);
|
||||
const rec = mockHashes.get(key);
|
||||
if (rec) rec.timestamp = job.completedAt;
|
||||
}, delayMs);
|
||||
|
||||
return { jobId };
|
||||
return { jobId, sha256: key, existing: false };
|
||||
}
|
||||
|
||||
async function mockGetStatus(jobId) {
|
||||
|
|
@ -91,6 +122,24 @@ async function mockGetStatus(jobId) {
|
|||
completedAt: job.completedAt,
|
||||
metadata: job.metadata,
|
||||
error: job.error,
|
||||
sha256: job.sha256,
|
||||
};
|
||||
}
|
||||
|
||||
async function mockLookupHash(sha256) {
|
||||
const key = String(sha256 || '').toLowerCase();
|
||||
const rec = mockHashes.get(key);
|
||||
if (!rec) {
|
||||
throw new AppError('Hash not found', { status: 404, code: 'NOT_FOUND' });
|
||||
}
|
||||
const job = mockJobs.get(rec.jobId);
|
||||
return {
|
||||
sha256: key,
|
||||
exists: true,
|
||||
jobId: rec.jobId,
|
||||
timestamp: rec.timestamp ?? job?.completedAt,
|
||||
status: job?.status,
|
||||
publicMetadata: job?.publicMetadata ?? rec.publicMetadata ?? {},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -184,7 +233,20 @@ export const veraeClient = {
|
|||
*/
|
||||
async createTimestamp(token, body) {
|
||||
if (config.mockVerae) return mockCreateTimestamp(body);
|
||||
return request('/api/timestamp', { method: 'POST', token, body });
|
||||
const liveBody = { data: body.data, hashAlg: body.hashAlg };
|
||||
return request('/api/timestamp', { method: 'POST', token, body: liveBody });
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} token
|
||||
* @param {string} sha256
|
||||
*/
|
||||
async lookupHash(token, sha256) {
|
||||
if (config.mockVerae) return mockLookupHash(sha256);
|
||||
throw new AppError('Hash lookup is not on the live Verae OpenAPI', {
|
||||
status: 501,
|
||||
code: 'NOT_IMPLEMENTED',
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -284,4 +346,5 @@ export const veraeClient = {
|
|||
*/
|
||||
export function clearMockJobs() {
|
||||
mockJobs.clear();
|
||||
mockHashes.clear();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,8 @@ export const config = {
|
|||
tokenSecret: process.env.TOKEN_SECRET ?? 'dev-secret-change-me',
|
||||
jobPollIntervalMs: int(process.env.JOB_POLL_INTERVAL_MS, 2000),
|
||||
jobPollMaxAttempts: int(process.env.JOB_POLL_MAX_ATTEMPTS, 60),
|
||||
waitTimeoutMs: int(process.env.WAIT_TIMEOUT_MS, 25000),
|
||||
mockJobCompleteMs: int(process.env.MOCK_JOB_COMPLETE_MS, 150),
|
||||
storePath: resolve(rootDir, process.env.STORE_PATH ?? './data/store.json'),
|
||||
upgradeUrl: process.env.UPGRADE_URL ?? 'https://veraetime.net/billing',
|
||||
adminSecret: process.env.ADMIN_SECRET ?? 'change-me-admin',
|
||||
|
|
|
|||
|
|
@ -43,6 +43,11 @@ export async function connectNats(url = config.natsUrl) {
|
|||
return { nc, js, jsm };
|
||||
}
|
||||
|
||||
/** @returns {import('nats').NatsConnection|null} */
|
||||
export function getNatsConnection() {
|
||||
return nc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Idempotently create JetStream streams required by this middleware.
|
||||
*
|
||||
|
|
|
|||
59
packages/verae-zapier-middleware/src/nats/wait.js
Normal file
59
packages/verae-zapier-middleware/src/nats/wait.js
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* Wait for a terminal job event on NATS JOBS_EVENTS.
|
||||
* @module nats/wait
|
||||
*/
|
||||
|
||||
import { createDebugger } from '../debug/logger.js';
|
||||
import { getTraceId } from '../debug/trace-context.js';
|
||||
import { SUBJECTS } from './subjects.js';
|
||||
import { connectNats, getNatsConnection } from './connection.js';
|
||||
|
||||
const log = createDebugger('jobs');
|
||||
|
||||
/**
|
||||
* @param {string} jobId
|
||||
* @param {number} timeoutMs
|
||||
* @returns {Promise<object|null>} event payload or null on timeout
|
||||
*/
|
||||
export async function waitForJobEvent(jobId, timeoutMs) {
|
||||
const handles = getNatsConnection() ? { nc: getNatsConnection() } : await connectNats();
|
||||
const nc = handles.nc;
|
||||
const sub = nc.subscribe(SUBJECTS.JOBS_EVENTS);
|
||||
const traceId = getTraceId();
|
||||
log.debug('waitForJobEvent subscribe', { jobId, timeoutMs, traceId });
|
||||
|
||||
const timeout = new Promise((resolve) => {
|
||||
setTimeout(() => resolve(null), timeoutMs);
|
||||
});
|
||||
|
||||
const firstMatch = (async () => {
|
||||
for await (const msg of sub) {
|
||||
let data;
|
||||
try {
|
||||
data = JSON.parse(typeof msg.string === 'function' ? msg.string() : msg.data);
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
if (data.jobId !== jobId) continue;
|
||||
const event = data.event;
|
||||
if (
|
||||
event === 'timestamp.completed' ||
|
||||
event === 'timestamp.failed' ||
|
||||
event === 'timestamp.timeout'
|
||||
) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
})();
|
||||
|
||||
try {
|
||||
return await Promise.race([firstMatch, timeout]);
|
||||
} finally {
|
||||
try {
|
||||
sub.unsubscribe();
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
}
|
||||
21
packages/verae-zapier-middleware/src/routes/hashRoutes.js
Normal file
21
packages/verae-zapier-middleware/src/routes/hashRoutes.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* @module routes/hashRoutes
|
||||
*/
|
||||
|
||||
import { Router } from 'express';
|
||||
import { asyncHandler, AppError } from '../errors.js';
|
||||
import { lookupHash } from '../services/timestampService.js';
|
||||
|
||||
export const hashRoutes = Router();
|
||||
|
||||
hashRoutes.get(
|
||||
'/:sha256',
|
||||
asyncHandler(async (req, res) => {
|
||||
const { sha256 } = req.params;
|
||||
if (!sha256 || !/^[a-fA-F0-9]{64}$/.test(sha256)) {
|
||||
throw new AppError('sha256 must be 64 hex chars', { status: 400, code: 'VALIDATION_ERROR' });
|
||||
}
|
||||
const result = await lookupHash(req.auth, sha256);
|
||||
res.json(result);
|
||||
}),
|
||||
);
|
||||
|
|
@ -10,6 +10,7 @@ import { verifyRoutes } from './verifyRoutes.js';
|
|||
import { statusRoutes } from './statusRoutes.js';
|
||||
import { webhookRoutes } from './webhookRoutes.js';
|
||||
import { publicTenantRoutes, adminTenantRoutes } from './tenantRoutes.js';
|
||||
import { hashRoutes } from './hashRoutes.js';
|
||||
import { authenticate } from '../middleware/authenticate.js';
|
||||
import { rateLimit } from '../middleware/rateLimit.js';
|
||||
|
||||
|
|
@ -29,5 +30,6 @@ protectedRoutes.use('/timestamp', timestampRoutes);
|
|||
protectedRoutes.use('/verify', verifyRoutes);
|
||||
protectedRoutes.use('/status', statusRoutes);
|
||||
protectedRoutes.use('/webhooks', webhookRoutes);
|
||||
protectedRoutes.use('/hashes', hashRoutes);
|
||||
|
||||
apiRoutes.use('/v1', protectedRoutes);
|
||||
|
|
|
|||
|
|
@ -15,11 +15,17 @@ export const timestampRoutes = Router();
|
|||
timestampRoutes.post(
|
||||
'/',
|
||||
asyncHandler(async (req, res) => {
|
||||
const { data, hashAlg } = req.body ?? {};
|
||||
if (!data) {
|
||||
throw new AppError('data is required', { status: 400, code: 'VALIDATION_ERROR' });
|
||||
const { data, hashAlg, sha256, publicMetadata, privateMetadata } = req.body ?? {};
|
||||
if (!data && !sha256) {
|
||||
throw new AppError('data or sha256 is required', { status: 400, code: 'VALIDATION_ERROR' });
|
||||
}
|
||||
const result = await createTimestamp(req.auth, { data, hashAlg });
|
||||
const result = await createTimestamp(req.auth, {
|
||||
data,
|
||||
hashAlg,
|
||||
sha256,
|
||||
publicMetadata,
|
||||
privateMetadata,
|
||||
});
|
||||
res.status(202).json(result);
|
||||
}),
|
||||
);
|
||||
|
|
@ -27,11 +33,17 @@ timestampRoutes.post(
|
|||
timestampRoutes.post(
|
||||
'/wait',
|
||||
asyncHandler(async (req, res) => {
|
||||
const { data, hashAlg } = req.body ?? {};
|
||||
if (!data) {
|
||||
throw new AppError('data is required', { status: 400, code: 'VALIDATION_ERROR' });
|
||||
const { data, hashAlg, sha256, publicMetadata, privateMetadata } = req.body ?? {};
|
||||
if (!data && !sha256) {
|
||||
throw new AppError('data or sha256 is required', { status: 400, code: 'VALIDATION_ERROR' });
|
||||
}
|
||||
const result = await createTimestampAndWait(req.auth, { data, hashAlg });
|
||||
const result = await createTimestampAndWait(req.auth, {
|
||||
data,
|
||||
hashAlg,
|
||||
sha256,
|
||||
publicMetadata,
|
||||
privateMetadata,
|
||||
});
|
||||
res.json(result);
|
||||
}),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ async function enqueueWatchForJob(ctx, jobId) {
|
|||
|
||||
/**
|
||||
* @param {object} ctx - Auth context with tenantId, veraeToken
|
||||
* @param {{ data: string, hashAlg?: string }} body
|
||||
* @returns {Promise<{ jobId: string }>}
|
||||
* @param {{ data?: string, hashAlg?: string, sha256?: string, publicMetadata?: object, privateMetadata?: object }} body
|
||||
* @returns {Promise<{ jobId: string, sha256?: string, existing?: boolean }>}
|
||||
*/
|
||||
export async function createTimestamp(ctx, body) {
|
||||
checkEntitlement(ctx.tenantId, 'timestamp');
|
||||
|
|
@ -66,12 +66,39 @@ export async function createTimestamp(ctx, body) {
|
|||
*/
|
||||
export async function createTimestampAndWait(ctx, body) {
|
||||
const created = await createTimestamp(ctx, body);
|
||||
|
||||
if (config.natsEnabled) {
|
||||
const { waitForJobEvent } = await import('../nats/wait.js');
|
||||
const event = await waitForJobEvent(created.jobId, config.waitTimeoutMs);
|
||||
if (event?.status) {
|
||||
recordUsage(ctx.tenantId, 'status');
|
||||
log.debug('wait via NATS event', {
|
||||
jobId: created.jobId,
|
||||
event: event.event,
|
||||
traceId: event.traceId,
|
||||
});
|
||||
return event.status;
|
||||
}
|
||||
const status = await veraeClient.getStatus(ctx.veraeToken, created.jobId);
|
||||
recordUsage(ctx.tenantId, 'status');
|
||||
if (status.status === 'pending') {
|
||||
return { id: created.jobId, jobId: created.jobId, status: 'pending' };
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
try {
|
||||
const status = await veraeClient.waitForJob(ctx.veraeToken, created.jobId, {
|
||||
maxAttempts: config.jobPollMaxAttempts,
|
||||
intervalMs: config.jobPollIntervalMs,
|
||||
});
|
||||
recordUsage(ctx.tenantId, 'status');
|
||||
return status;
|
||||
} catch {
|
||||
const status = await veraeClient.getStatus(ctx.veraeToken, created.jobId);
|
||||
recordUsage(ctx.tenantId, 'status');
|
||||
return { id: created.jobId, jobId: created.jobId, status: status.status ?? 'pending' };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -120,3 +147,13 @@ export async function getJobVerification(ctx, jobId) {
|
|||
recordUsage(ctx.tenantId, 'status');
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} ctx
|
||||
* @param {string} sha256
|
||||
*/
|
||||
export async function lookupHash(ctx, sha256) {
|
||||
const result = await veraeClient.lookupHash(ctx.veraeToken, sha256);
|
||||
recordUsage(ctx.tenantId, 'status');
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
/**
|
||||
* Hash idempotent register + lookup (mock Verae)
|
||||
*/
|
||||
|
||||
import { describe, it, before, after } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import http from 'node:http';
|
||||
import { createApp } from '../../src/app.js';
|
||||
import { useTempStore, seedProTenant } from '../helpers.js';
|
||||
import { clearMockJobs, sha256Hex } from '../../src/clients/veraeClient.js';
|
||||
import { config } from '../../src/config.js';
|
||||
|
||||
describe('hash register + lookup', () => {
|
||||
let ctx;
|
||||
/** @type {import('http').Server} */
|
||||
let server;
|
||||
let port;
|
||||
let apiKey;
|
||||
|
||||
before(async () => {
|
||||
config.mockVerae = true;
|
||||
config.natsEnabled = false;
|
||||
clearMockJobs();
|
||||
ctx = useTempStore();
|
||||
const seeded = seedProTenant();
|
||||
apiKey = seeded.apiKey;
|
||||
const app = createApp();
|
||||
await new Promise((resolve) => {
|
||||
server = app.listen(0, '127.0.0.1', () => {
|
||||
port = server.address().port;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await new Promise((r) => server.close(r));
|
||||
ctx.cleanup();
|
||||
});
|
||||
|
||||
it('registers sha256, second create returns original jobId', async () => {
|
||||
const data = 'hello-hash';
|
||||
const sha = sha256Hex(data);
|
||||
const r1 = await json(port, 'POST', '/zapier/v1/timestamp', apiKey, { data });
|
||||
assert.equal(r1.status, 202);
|
||||
const r2 = await json(port, 'POST', '/zapier/v1/timestamp', apiKey, { sha256: sha });
|
||||
assert.equal(r2.status, 202);
|
||||
assert.equal(r2.body.jobId, r1.body.jobId);
|
||||
assert.equal(r2.body.existing, true);
|
||||
|
||||
const look = await json(port, 'GET', `/zapier/v1/hashes/${sha}`, apiKey);
|
||||
assert.equal(look.status, 200);
|
||||
assert.equal(look.body.exists, true);
|
||||
assert.equal(look.body.jobId, r1.body.jobId);
|
||||
});
|
||||
|
||||
it('lookup miss is 404', async () => {
|
||||
const miss = 'a'.repeat(64);
|
||||
const look = await json(port, 'GET', `/zapier/v1/hashes/${miss}`, apiKey);
|
||||
assert.equal(look.status, 404);
|
||||
});
|
||||
});
|
||||
|
||||
function json(port, method, path, apiKey, body) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const req = http.request(
|
||||
{
|
||||
hostname: '127.0.0.1',
|
||||
port,
|
||||
path,
|
||||
method,
|
||||
headers: {
|
||||
authorization: `Bearer ${apiKey}`,
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
},
|
||||
(res) => {
|
||||
let data = '';
|
||||
res.on('data', (c) => {
|
||||
data += c;
|
||||
});
|
||||
res.on('end', () => {
|
||||
let parsed = {};
|
||||
try {
|
||||
parsed = data ? JSON.parse(data) : {};
|
||||
} catch {
|
||||
parsed = { raw: data };
|
||||
}
|
||||
resolve({ status: res.statusCode, body: parsed });
|
||||
});
|
||||
},
|
||||
);
|
||||
req.on('error', reject);
|
||||
if (body) req.write(JSON.stringify(body));
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* GATE 9 — /timestamp/wait via NATS events (timeout returns pending + jobId)
|
||||
*/
|
||||
|
||||
import { describe, it, before, after } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { config } from '../../src/config.js';
|
||||
import { useTempStore, seedProTenant } from '../helpers.js';
|
||||
import { connectNats, ensureStreams, closeNats } from '../../src/nats/connection.js';
|
||||
import { startJobPollerWorker, stopJobPollerWorker } from '../../src/workers/jobPollerWorker.js';
|
||||
import { createTimestampAndWait } from '../../src/services/timestampService.js';
|
||||
import { resolveAuthContext } from '../../src/services/authService.js';
|
||||
import { clearMockJobs } from '../../src/clients/veraeClient.js';
|
||||
|
||||
describe('GATE 9 wait via NATS', () => {
|
||||
/** @type {ReturnType<typeof useTempStore>} */
|
||||
let ctx;
|
||||
let authCtx;
|
||||
|
||||
before(async () => {
|
||||
assert.equal(config.mockVerae, true);
|
||||
config.natsEnabled = true;
|
||||
process.env.NATS_FORCE_CONNECT = '1';
|
||||
config.natsUrl = process.env.NATS_URL || 'nats://127.0.0.1:4222';
|
||||
config.jobPollIntervalMs = 40;
|
||||
config.jobPollMaxAttempts = 40;
|
||||
config.waitTimeoutMs = 8000;
|
||||
config.mockJobCompleteMs = 80;
|
||||
|
||||
clearMockJobs();
|
||||
ctx = useTempStore();
|
||||
const seeded = seedProTenant();
|
||||
authCtx = await resolveAuthContext(seeded.apiKey);
|
||||
|
||||
await connectNats(config.natsUrl);
|
||||
await ensureStreams();
|
||||
await startJobPollerWorker();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await stopJobPollerWorker();
|
||||
await closeNats();
|
||||
ctx.cleanup();
|
||||
process.env.NATS_FORCE_CONNECT = '';
|
||||
});
|
||||
|
||||
it('wait returns completed when worker finishes before timeout', async () => {
|
||||
const status = await createTimestampAndWait(authCtx, { data: 'wait-fast' });
|
||||
assert.equal(status.status, 'completed');
|
||||
assert.ok(status.id || status.jobId);
|
||||
});
|
||||
|
||||
it('wait returns pending + jobId on timeout', async () => {
|
||||
const prevWait = config.waitTimeoutMs;
|
||||
const prevDelay = config.mockJobCompleteMs;
|
||||
config.waitTimeoutMs = 60;
|
||||
config.mockJobCompleteMs = 30_000;
|
||||
try {
|
||||
const status = await createTimestampAndWait(authCtx, { data: 'wait-slow' });
|
||||
assert.equal(status.status, 'pending');
|
||||
assert.ok(status.jobId || status.id);
|
||||
} finally {
|
||||
config.waitTimeoutMs = prevWait;
|
||||
config.mockJobCompleteMs = prevDelay;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -18,6 +18,7 @@ describe('config', () => {
|
|||
'tokenSecret',
|
||||
'jobPollIntervalMs',
|
||||
'jobPollMaxAttempts',
|
||||
'waitTimeoutMs',
|
||||
'storePath',
|
||||
]) {
|
||||
assert.notEqual(config[key], undefined, `missing config.${key}`);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ const verifyTimestamp = require('./creates/verify_timestamp');
|
|||
const batchTimestamp = require('./creates/batch_timestamp');
|
||||
const addNumbers = require('./creates/add_numbers');
|
||||
const jobStatus = require('./searches/job_status');
|
||||
const hashLookup = require('./searches/hash_lookup');
|
||||
const timestampCompleted = require('./triggers/timestamp_completed');
|
||||
|
||||
/**
|
||||
|
|
@ -74,5 +75,6 @@ module.exports = {
|
|||
},
|
||||
searches: {
|
||||
[jobStatus.key]: jobStatus,
|
||||
[hashLookup.key]: hashLookup,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
34
packages/verae-zapier/searches/hash_lookup.js
Normal file
34
packages/verae-zapier/searches/hash_lookup.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
const base = () => process.env.MIDDLEWARE_BASE_URL || 'http://127.0.0.1:3100';
|
||||
|
||||
const perform = async (z, bundle) => {
|
||||
try {
|
||||
const response = await z.request({
|
||||
method: 'GET',
|
||||
url: `${base()}/zapier/v1/hashes/${encodeURIComponent(bundle.inputData.sha256)}`,
|
||||
});
|
||||
return [response.data];
|
||||
} catch (err) {
|
||||
if (err.status === 404) return [];
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
key: 'hash_lookup',
|
||||
noun: 'Timestamp',
|
||||
display: {
|
||||
label: 'Find Timestamp by SHA256',
|
||||
description: 'Looks up an existing timestamp for a SHA256 hex digest (mock/middleware).',
|
||||
},
|
||||
operation: {
|
||||
inputFields: [
|
||||
{ key: 'sha256', label: 'SHA256', type: 'string', required: true },
|
||||
],
|
||||
perform,
|
||||
sample: {
|
||||
sha256: '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824',
|
||||
exists: true,
|
||||
jobId: '550e8400-e29b-41d4-a716-446655440000',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -27,6 +27,7 @@ describe('verae-zapier app definition', () => {
|
|||
assert.ok(App.creates.verify_timestamp);
|
||||
assert.ok(App.creates.batch_timestamp);
|
||||
assert.ok(App.searches.job_status);
|
||||
assert.ok(App.searches.hash_lookup);
|
||||
assert.ok(App.triggers.timestamp_completed);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -58,6 +58,41 @@ paths:
|
|||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
/v1/timestamp:
|
||||
post:
|
||||
operationId: timestamp
|
||||
summary: Register a timestamp (proxies middleware or in-process mock)
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: string
|
||||
sha256:
|
||||
type: string
|
||||
hashAlg:
|
||||
type: string
|
||||
responses:
|
||||
'202':
|
||||
description: Accepted
|
||||
/v1/hashes/{sha256}:
|
||||
get:
|
||||
operationId: hash-lookup
|
||||
summary: Lookup a SHA256 timestamp (mock)
|
||||
parameters:
|
||||
- name: sha256
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
'404':
|
||||
description: Missing
|
||||
/v1/add:
|
||||
post:
|
||||
operationId: add
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import path from 'path';
|
||||
import { randomUUID } from 'crypto';
|
||||
import { createHash, randomUUID } from 'crypto';
|
||||
import express, { Express, NextFunction, Request, RequestHandler, Response } from 'express';
|
||||
import * as OpenApiValidator from 'express-openapi-validator';
|
||||
import swaggerUi from 'swagger-ui-express';
|
||||
|
|
@ -97,6 +97,10 @@ export function buildApp(deps: AppDeps = {}): {
|
|||
},
|
||||
};
|
||||
const items: StoredItem[] = [];
|
||||
const hashIndex = new Map<
|
||||
string,
|
||||
{ jobId: string; sha256: string; data?: string; timestamp: string }
|
||||
>();
|
||||
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
|
|
@ -157,6 +161,36 @@ export function buildApp(deps: AppDeps = {}): {
|
|||
res.json({ output: text.toUpperCase(), quote: res.locals.quote });
|
||||
});
|
||||
|
||||
app.post('/v1/timestamp', meter('timestamp', usage, pricing), (req, res) => {
|
||||
const data = req.body?.data != null ? String(req.body.data) : '';
|
||||
const sha256 =
|
||||
(req.body?.sha256 && String(req.body.sha256).toLowerCase()) ||
|
||||
(data ? createHash('sha256').update(data, 'utf8').digest('hex') : '');
|
||||
if (!sha256) {
|
||||
res.status(400).json({ error: 'data or sha256 is required' });
|
||||
return;
|
||||
}
|
||||
const existing = hashIndex.get(sha256);
|
||||
if (existing) {
|
||||
res.status(202).json({ jobId: existing.jobId, sha256, existing: true, timestamp: existing.timestamp });
|
||||
return;
|
||||
}
|
||||
const jobId = randomUUID();
|
||||
const timestamp = new Date().toISOString();
|
||||
hashIndex.set(sha256, { jobId, sha256, data, timestamp });
|
||||
res.status(202).json({ jobId, sha256, existing: false, timestamp });
|
||||
});
|
||||
|
||||
app.get('/v1/hashes/:sha256', meter('hash-lookup', usage, pricing), (req, res) => {
|
||||
const sha256 = String(req.params.sha256 || '').toLowerCase();
|
||||
const rec = hashIndex.get(sha256);
|
||||
if (!rec) {
|
||||
res.status(404).json({ error: 'Hash not found' });
|
||||
return;
|
||||
}
|
||||
res.json({ exists: true, ...rec });
|
||||
});
|
||||
|
||||
app.post('/v1/add', meter('add', usage, pricing), (req, res) => {
|
||||
const number1 = Number(req.body?.number1);
|
||||
const number2 = Number(req.body?.number2);
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ export const DEFAULT_RATE_CARD: RateCard = {
|
|||
'storage-list': { kind: 'free' },
|
||||
transform: { kind: 'fixed', fixedCents: 4 },
|
||||
add: { kind: 'free' },
|
||||
timestamp: { kind: 'fixed', fixedCents: 4 },
|
||||
'hash-lookup': { kind: 'free' },
|
||||
storage: { kind: 'variable', baseCents: 10, perKbCents: 1, perMbCents: 50 },
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,6 +18,26 @@ describe('Zappier API', () => {
|
|||
expect(res.body.quote.totalCents).toBe(0);
|
||||
});
|
||||
|
||||
it('POST /v1/timestamp is idempotent by sha256', async () => {
|
||||
const { app } = buildApp();
|
||||
const a = await request(app)
|
||||
.post('/v1/timestamp')
|
||||
.set('x-api-key', KEY)
|
||||
.send({ data: 'abc' });
|
||||
expect(a.status).toBe(202);
|
||||
const b = await request(app)
|
||||
.post('/v1/timestamp')
|
||||
.set('x-api-key', KEY)
|
||||
.send({ data: 'abc' });
|
||||
expect(b.body.jobId).toBe(a.body.jobId);
|
||||
expect(b.body.existing).toBe(true);
|
||||
const look = await request(app)
|
||||
.get(`/v1/hashes/${a.body.sha256}`)
|
||||
.set('x-api-key', KEY);
|
||||
expect(look.status).toBe(200);
|
||||
expect(look.body.jobId).toBe(a.body.jobId);
|
||||
});
|
||||
|
||||
it('POST /v1/add returns the sum and is free', async () => {
|
||||
const { app } = buildApp();
|
||||
const res = await request(app)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue