@tangle-network/hub-sdk 0.19.2-develop.20260808074903.e05182e → 0.19.2
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 +87 -6
- package/dist/index.d.ts +444 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +304 -216
- package/dist/index.js.map +1 -1
- package/package.json +8 -4
package/README.md
CHANGED
|
@@ -30,9 +30,7 @@ SaaS vs on-prem flips via env only — there is no per-client default URL.
|
|
|
30
30
|
| `TANGLE_API_KEY` | One of | Long-lived API key (Bearer). User / API key principal. |
|
|
31
31
|
| `TANGLE_HUB_CAPABILITY_TOKEN` | One of | Short-lived capability token (Bearer). Sandbox-runtime principal. Auto-minted server-side per action. |
|
|
32
32
|
|
|
33
|
-
The two auth credentials are mutually exclusive — set exactly one.
|
|
34
|
-
mirrors the platform-api `hubSandboxEnvironmentSchema` rule
|
|
35
|
-
(`exactly-one-api-key-or-capability-token`).
|
|
33
|
+
The two auth credentials are mutually exclusive — set exactly one.
|
|
36
34
|
|
|
37
35
|
### Examples
|
|
38
36
|
|
|
@@ -218,19 +216,102 @@ product does not need a second workflow-run request.
|
|
|
218
216
|
Callbacks may be retried; use `delivery.runId` as the durable idempotency key
|
|
219
217
|
before starting product work.
|
|
220
218
|
|
|
219
|
+
## Allowances and the paywall decision
|
|
220
|
+
|
|
221
|
+
A product that bills its end users sets a free allowance, and optionally a paid one, on a meter.
|
|
222
|
+
Hub admits every turn against it, counts turns per member and per line, and reads each payer's dollars from the ledger.
|
|
223
|
+
The product keeps only its checkout: after a payment it records the member as paid until the period ends.
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
await hub.allowances.setPlan(`agent:${agentId}`, {
|
|
227
|
+
free: { turnsPerDay: 20, usdPerDay: 2 },
|
|
228
|
+
paid: { turnsPerDay: 200, usdPerDay: 5, priceUsdMonthly: 10 },
|
|
229
|
+
spendResourceType: "hosted_enrollment",
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const turn = await hub.allowances.admit(`agent:${agentId}`, {
|
|
233
|
+
member: enrollmentId,
|
|
234
|
+
turnId: messageId,
|
|
235
|
+
line: lineId,
|
|
236
|
+
});
|
|
237
|
+
if (turn.decision === "paywall") return sendCheckoutLink();
|
|
238
|
+
if (turn.decision === "allowance_reached") return sendComeBackTomorrow();
|
|
239
|
+
|
|
240
|
+
// From the checkout webhook:
|
|
241
|
+
await hub.allowances.grant(`agent:${agentId}`, enrollmentId, {
|
|
242
|
+
expiresAt: periodEnd.toISOString(),
|
|
243
|
+
reference: subscriptionId,
|
|
244
|
+
});
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
`admit` is idempotent by `turnId`, so a retried turn is never counted twice.
|
|
248
|
+
A member's dollars are the sum of today's ledger charges on keys bound to `(spendResourceType, member)` and on every key delegated below them, so delegate each member's key with that resource.
|
|
249
|
+
A paid member also has a funded capacity for the period: the price less Tangle's 10% fee, plus the free daily dollars for the period's 31 days.
|
|
250
|
+
With the plan above, that is $9 + $62 = $71 against the $155 that $5 a day would allow.
|
|
251
|
+
Past it, `admit` answers `allowance_reached`, and `turn.period` shows `spent`, `funded` and `remaining`.
|
|
252
|
+
Only the meter's owner may call these, signed in or with a root key of their own.
|
|
253
|
+
A delegated or resource-bound key is refused, so an end user's sandbox cannot grant itself the paid tier.
|
|
254
|
+
|
|
221
255
|
## Exports
|
|
222
256
|
|
|
223
257
|
- `HubClient`, `HubClient.fromEnv(options?)`
|
|
224
258
|
- `HubConnectionsClient`, `HubPermissionsClient`, `HubTokensClient`,
|
|
225
259
|
`HubChannelsClient`, `HubEventSubscriptionsClient`, `HubToolsClient`,
|
|
226
|
-
`HubApprovalsClient`, `HubAuditClient`, `HubWorkflowsClient
|
|
260
|
+
`HubApprovalsClient`, `HubAuditClient`, `HubWorkflowsClient`,
|
|
261
|
+
`HubAllowancesClient`
|
|
227
262
|
- `deriveHubEventCallbackSecret`, `authenticateHubEventRequest`,
|
|
228
263
|
`verifyHubEventSignature`, `parseHubEventDelivery`, `HubEventDeliveryError`
|
|
229
264
|
- `HubSdkError` — typed `code: HubErrorCode`, redacted `details`, optional
|
|
230
265
|
HTTP `status`
|
|
231
266
|
- `HUB_URL_ENV_VAR`, `HUB_API_KEY_ENV_VAR`, `HUB_CAPABILITY_TOKEN_ENV_VAR` —
|
|
232
|
-
string constants for the env-var names
|
|
233
|
-
`hub-sandbox-contract.ts` `z.literal(...)`)
|
|
267
|
+
string constants for the env-var names
|
|
234
268
|
- `resolveHubBaseUrl(env?)`, `resolveHubAuth(env?)` — standalone resolvers
|
|
235
269
|
with the same fail-loud contract as `fromEnv`
|
|
236
270
|
- All request/response types from the `/v1/hub/*` contract
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
## Link application login to explicit Hub permissions
|
|
274
|
+
|
|
275
|
+
Use the same `HubClient` for application management; do not add a product-local
|
|
276
|
+
HTTP client. These operations require the authenticated developer account, not
|
|
277
|
+
an app's OIDC access token. Customer grants are created only by the existing
|
|
278
|
+
session-authenticated `/cross-site/app-consent` flow.
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
import { HubClient } from "@tangle-network/hub-sdk";
|
|
282
|
+
|
|
283
|
+
const hub = HubClient.fromEnv(); // developer account for app administration
|
|
284
|
+
const { app, clientSecret } = await hub.apps.create({
|
|
285
|
+
name: "Support assistant",
|
|
286
|
+
redirectUris: ["https://assistant.example/hub/callback"],
|
|
287
|
+
allowedScopes: ["github.issues.create"],
|
|
288
|
+
});
|
|
289
|
+
// Save clientSecret once in the application's server-side secret store.
|
|
290
|
+
await hub.apps.linkOAuthClient(app.id, oidcClientId);
|
|
291
|
+
const apps = await hub.apps.list(); // includes oauthClientId; never the secret
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
`oidcClientId` is the application's already-registered Sign in with Tangle client.
|
|
295
|
+
Linking requires the same owner on both records and is immutable and one-to-one.
|
|
296
|
+
It does not reuse the two clients' secrets, change their IDs, create a user grant,
|
|
297
|
+
or authorize spending. Use separate app/client pairs for separate deployments.
|
|
298
|
+
Existing unlinked broker apps remain compatible. There is no automatic link by
|
|
299
|
+
name, callback domain, email, or ownership alone.
|
|
300
|
+
|
|
301
|
+
With a customer's authenticated Hub client, `hub.apps.grants.list()` returns only
|
|
302
|
+
that customer's active resource grants and `hub.apps.grants.revoke(grantId)`
|
|
303
|
+
revokes one idempotently. App administrators use `hub.apps.revoke(appId)` to
|
|
304
|
+
suspend the app, revoke all its customer grants, and disable its owned linked
|
|
305
|
+
OIDC client. An app's broker credential cannot call these management methods.
|
|
306
|
+
|
|
307
|
+
Broker execution keeps the one approved connection even when the invocation
|
|
308
|
+
omits `connectionId`; it never substitutes another account. Each one-shot broker
|
|
309
|
+
token is checked against current app policy and the exact active grant when
|
|
310
|
+
minted and consumed. Changing consent revokes the old binding, tokens and codes;
|
|
311
|
+
the fresh consent response supplies a new grant ID. Login disconnect revokes the
|
|
312
|
+
linked app's existing grants for that customer, not other customers or apps.
|
|
313
|
+
An operation already admitted to a provider may finish; revocation blocks new
|
|
314
|
+
admissions and minting, not external side effects already underway.
|
|
315
|
+
|
|
316
|
+
This is identity and resource delegation, **not** generalized spending delegation.
|
|
317
|
+
Existing product billing checks and action approvals continue to apply.
|