@t3b/hub-guard 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/dist/hub-client.d.ts +20 -0
- package/dist/hub-client.js +11 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -74,6 +74,22 @@ await audit(cfg, { action: "shopify.write", target: "kw", detail: { what: "produ
|
|
|
74
74
|
Without a Vercel ID (OIDC switched off, or a local run without `VERCEL_OIDC_TOKEN`) nothing is
|
|
75
75
|
sent and the answer says why (`no_vercel_id`).
|
|
76
76
|
|
|
77
|
+
## Telling the Hub something is wrong (0.3.0)
|
|
78
|
+
|
|
79
|
+
An app never emails anyone itself: it tells the Hub, and the Hub emails the people chosen in
|
|
80
|
+
Settings → Alerts — one email, at most one reminder a day while it lasts, one "back to normal".
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
import { alert } from "@t3b/hub-guard";
|
|
84
|
+
const cfg = { hubUrl: process.env.T3B_HUB_URL ?? "https://t3b-hub.com" };
|
|
85
|
+
await alert(cfg, { key: "rates-follow", ok: false, title: "MyFatoorah rates not followed for 30 hours", detail: "the 06:00 run failed: timeout", fix: "Nothing to do if tomorrow's run works." });
|
|
86
|
+
await alert(cfg, { key: "rates-follow", ok: true }); // it is over: one "back to normal" if you were told
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`key`: lower-case letters, digits and `._:-`, up to 80 — the app's own name for the problem.
|
|
90
|
+
`title` up to 120 characters, `detail` 500, `fix` 300, `store` a store key. No secrets, tokens
|
|
91
|
+
or customer data in any of them. At most 120 reports an hour per app.
|
|
92
|
+
|
|
77
93
|
## Shopify's events (through the Hub)
|
|
78
94
|
|
|
79
95
|
The module never holds the Shopify app secret. Shopify sends events to the Hub; the Hub checks
|
|
@@ -141,6 +157,7 @@ export const GET = (req: Request) => guard.enter(req);
|
|
|
141
157
|
|
|
142
158
|
## Changes
|
|
143
159
|
|
|
160
|
+
- **0.3.0** (WORKFLOWS 9.3): `alert()` — report a problem to the Hub, or say it is over.
|
|
144
161
|
- **0.2.0** (8b): no module key and no pasted Hub public key. Hub → module: tokens signed by the Hub's key published at `/api/hub/jwks` (`verifyTicket`, `verifyRelay`, `verifyHubCall`, `manifestResponse`, `healthResponse`). Module → Hub: the app's own Vercel ID (`tokenBroker`, `audit`, `sessionCheck`). Removed: `signedManifest`, `relaySignature`, `importPublicKey`, the `moduleKey` / `hubPublicKeys` settings. `Guard` takes `sessionSecret`.
|
|
145
162
|
- **0.1.1**: `enter()` answers with an absolute Location (B-016).
|
|
146
163
|
- **0.1.0**: first publish, Web Crypto build.
|
package/dist/hub-client.d.ts
CHANGED
|
@@ -33,6 +33,26 @@ export declare function audit(cfg: HubClientConfig, line: {
|
|
|
33
33
|
target?: string;
|
|
34
34
|
detail?: Record<string, unknown>;
|
|
35
35
|
}): Promise<boolean>;
|
|
36
|
+
/**
|
|
37
|
+
* 9.3: tell the Hub a problem started (`ok: false`, with a title) or ended (`ok: true`), under a
|
|
38
|
+
* key of the app's own ("rates-follow", "feeds"). The Hub emails under its no-flood rule; the app
|
|
39
|
+
* never emails anyone itself. Never throws.
|
|
40
|
+
*/
|
|
41
|
+
export declare function alert(cfg: HubClientConfig, a: {
|
|
42
|
+
key: string;
|
|
43
|
+
ok: boolean;
|
|
44
|
+
title?: string;
|
|
45
|
+
detail?: string;
|
|
46
|
+
fix?: string;
|
|
47
|
+
store?: string;
|
|
48
|
+
}): Promise<{
|
|
49
|
+
ok: true;
|
|
50
|
+
state: string;
|
|
51
|
+
} | {
|
|
52
|
+
ok: false;
|
|
53
|
+
status: number;
|
|
54
|
+
error: string;
|
|
55
|
+
}>;
|
|
36
56
|
export type HubCallCheck = {
|
|
37
57
|
ok: true;
|
|
38
58
|
} | {
|
package/dist/hub-client.js
CHANGED
|
@@ -63,6 +63,17 @@ export async function audit(cfg, line) {
|
|
|
63
63
|
const r = await post(cfg, "/api/hub/audit", line);
|
|
64
64
|
return r.status === 200 || r.status === 201;
|
|
65
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* 9.3: tell the Hub a problem started (`ok: false`, with a title) or ended (`ok: true`), under a
|
|
68
|
+
* key of the app's own ("rates-follow", "feeds"). The Hub emails under its no-flood rule; the app
|
|
69
|
+
* never emails anyone itself. Never throws.
|
|
70
|
+
*/
|
|
71
|
+
export async function alert(cfg, a) {
|
|
72
|
+
const r = await post(cfg, "/api/hub/alerts", a);
|
|
73
|
+
if (r.status === 202)
|
|
74
|
+
return { ok: true, state: String(r.json?.state ?? "") };
|
|
75
|
+
return { ok: false, status: r.status, error: String(r.json?.field ?? r.json?.error ?? "no_answer") };
|
|
76
|
+
}
|
|
66
77
|
/** Is this request the Hub's own, for this module and this purpose? (`Authorization: Bearer <pass>`) */
|
|
67
78
|
export async function verifyHubCall(req, opts) {
|
|
68
79
|
const auth = req.headers.get("authorization") ?? "";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { Guard, type GuardConfig, type CheckResult } from "./guard.js";
|
|
2
2
|
export { verifyTicket, JtiMemory, TICKET_ISSUER, TICKET_TTL_S, TICKET_ALG, type TicketClaims, type VerifyResult } from "./ticket.js";
|
|
3
3
|
export { readSession, signSession, cookieHeader, clearCookieHeader, cookieValue, SESSION_COOKIE, IDLE_MS, ABSOLUTE_MS, RECHECK_MS, type ModuleSession } from "./session.js";
|
|
4
|
-
export { sessionCheck, tokenBroker, audit, verifyHubCall, manifestResponse, healthResponse, healthAnswer, type HubClientConfig, type HubCallCheck, type AnswerConfig, type BrokerToken, type Connection, } from "./hub-client.js";
|
|
4
|
+
export { sessionCheck, tokenBroker, audit, alert, verifyHubCall, manifestResponse, healthResponse, healthAnswer, type HubClientConfig, type HubCallCheck, type AnswerConfig, type BrokerToken, type Connection, } from "./hub-client.js";
|
|
5
5
|
export { checkCloudflareAccess } from "./cf-access.js";
|
|
6
6
|
export { verifyRelay, RELAY_HEADERS, RELAY_MAX_AGE_S, type RelayCheck } from "./relay.js";
|
|
7
7
|
export { ownVercelToken, ownEnvironment, hubKeys, APP_ID_HEADER, OIDC_HEADER, type TokenProvider } from "./identity.js";
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { Guard } from "./guard.js";
|
|
2
2
|
export { verifyTicket, JtiMemory, TICKET_ISSUER, TICKET_TTL_S, TICKET_ALG } from "./ticket.js";
|
|
3
3
|
export { readSession, signSession, cookieHeader, clearCookieHeader, cookieValue, SESSION_COOKIE, IDLE_MS, ABSOLUTE_MS, RECHECK_MS } from "./session.js";
|
|
4
|
-
export { sessionCheck, tokenBroker, audit, verifyHubCall, manifestResponse, healthResponse, healthAnswer, } from "./hub-client.js";
|
|
4
|
+
export { sessionCheck, tokenBroker, audit, alert, verifyHubCall, manifestResponse, healthResponse, healthAnswer, } from "./hub-client.js";
|
|
5
5
|
export { checkCloudflareAccess } from "./cf-access.js";
|
|
6
6
|
export { verifyRelay, RELAY_HEADERS, RELAY_MAX_AGE_S } from "./relay.js";
|
|
7
7
|
export { ownVercelToken, ownEnvironment, hubKeys, APP_ID_HEADER, OIDC_HEADER } from "./identity.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@t3b/hub-guard",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "The3Beez Hub guard: a module opens only by a Hub-signed ticket and refuses everything else. No key from the Hub: towards the Hub the app shows its own Vercel ID; from the Hub it accepts only what is signed by the key the Hub publishes. Entry route, refusal page, module session, idle rule, 15-minute re-check, Cloudflare Access proof, broker and audit clients, manifest and health answers for the Hub only. Web Crypto only: runs in Node 20+ and in edge runtimes.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|