@augustdigital/sdk 8.26.0 → 9.1.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/lib/adapters/stellar/actions.d.ts +13 -0
- package/lib/adapters/stellar/actions.js +51 -2
- package/lib/adapters/stellar/index.d.ts +12 -0
- package/lib/adapters/stellar/index.js +12 -0
- package/lib/adapters/stellar/invocation.d.ts +55 -0
- package/lib/adapters/stellar/invocation.js +92 -0
- package/lib/adapters/stellar/soroban.d.ts +8 -0
- package/lib/adapters/stellar/soroban.js +18 -4
- package/lib/adapters/stellar/submit.d.ts +8 -0
- package/lib/adapters/stellar/submit.js +46 -0
- package/lib/core/analytics/app-name.d.ts +27 -0
- package/lib/core/analytics/app-name.js +48 -0
- package/lib/core/analytics/env.d.ts +17 -0
- package/lib/core/analytics/env.js +88 -0
- package/lib/core/analytics/sentry.d.ts +16 -4
- package/lib/core/analytics/sentry.js +24 -29
- package/lib/core/analytics/version.d.ts +1 -1
- package/lib/core/analytics/version.js +1 -1
- package/lib/core/base.class.d.ts +26 -3
- package/lib/core/base.class.js +16 -31
- package/lib/core/logger/curator-alert.d.ts +217 -0
- package/lib/core/logger/curator-alert.js +276 -0
- package/lib/core/logger/index.d.ts +1 -0
- package/lib/core/logger/index.js +20 -1
- package/lib/sdk.d.ts +158 -7
- package/package.json +1 -1
|
@@ -12,16 +12,28 @@ export declare function resetErrorDedupe(): void;
|
|
|
12
12
|
* Initialize Sentry with SDK-specific configuration. Idempotent: re-calls
|
|
13
13
|
* only refresh user identity and the cached API-key hash.
|
|
14
14
|
*
|
|
15
|
+
* Breaking change in v9: `appName` moved from the optional fifth parameter
|
|
16
|
+
* to the required third parameter, so every telemetry stream carries an
|
|
17
|
+
* application identity (the `AugustSDK` constructor has required it since
|
|
18
|
+
* v5). Callers on the old positional order get a synchronous validation
|
|
19
|
+
* error rather than silently anonymous events.
|
|
20
|
+
*
|
|
15
21
|
* @param config - Analytics configuration. Pass `tracesSampleRate` to
|
|
16
22
|
* override the default of `0.1`.
|
|
17
23
|
* @param environment - Current environment (DEV or PROD).
|
|
24
|
+
* @param appName - App-name slug, required. Set as the global `app.name`
|
|
25
|
+
* tag on every event and used to derive `partner.id`. Identifier-shaped:
|
|
26
|
+
* 3–64 chars, `[a-zA-Z0-9._-]` only, and not an EVM address — the same
|
|
27
|
+
* rules the `AugustSDK` constructor enforces.
|
|
18
28
|
* @param walletAddress - Optional wallet address for user identification.
|
|
19
29
|
* @param apiKey - Optional API key (hashed for identification).
|
|
20
|
-
* @
|
|
21
|
-
*
|
|
22
|
-
*
|
|
30
|
+
* @throws AugustValidationError (code `INVALID_INPUT`) when `appName` is
|
|
31
|
+
* missing, empty, mis-typed, out of the allowed length range, contains
|
|
32
|
+
* disallowed characters, or is shaped like an EVM address. Thrown before
|
|
33
|
+
* any analytics state mutates, even when analytics would be disabled by
|
|
34
|
+
* config or environment gates.
|
|
23
35
|
*/
|
|
24
|
-
export declare function initializeSentry(config: IAnalyticsConfig, environment: IEnv,
|
|
36
|
+
export declare function initializeSentry(config: IAnalyticsConfig, environment: IEnv, appName: string, walletAddress?: string, apiKey?: string): void;
|
|
25
37
|
/**
|
|
26
38
|
* Update the current user identity in Sentry.
|
|
27
39
|
* Called when wallet address changes.
|
|
@@ -9,6 +9,7 @@ exports.getSentry = getSentry;
|
|
|
9
9
|
exports.resetAnalytics = resetAnalytics;
|
|
10
10
|
exports.captureSdkException = captureSdkException;
|
|
11
11
|
const logger_1 = require("../logger");
|
|
12
|
+
const app_name_1 = require("./app-name");
|
|
12
13
|
const constants_1 = require("./constants");
|
|
13
14
|
const env_1 = require("./env");
|
|
14
15
|
const sentry_runtime_1 = require("./sentry-runtime");
|
|
@@ -35,26 +36,6 @@ function getSDKVersion() {
|
|
|
35
36
|
return 'development';
|
|
36
37
|
}
|
|
37
38
|
}
|
|
38
|
-
/**
|
|
39
|
-
* Check if running on localhost.
|
|
40
|
-
*/
|
|
41
|
-
function isLocalhost() {
|
|
42
|
-
try {
|
|
43
|
-
if (typeof window !== 'undefined' && window.location) {
|
|
44
|
-
const hostname = window.location.hostname;
|
|
45
|
-
return (hostname === 'localhost' ||
|
|
46
|
-
hostname === '127.0.0.1' ||
|
|
47
|
-
hostname === '0.0.0.0' ||
|
|
48
|
-
hostname.startsWith('192.168.') ||
|
|
49
|
-
hostname.startsWith('10.') ||
|
|
50
|
-
hostname.endsWith('.local'));
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
catch {
|
|
54
|
-
// Silently fail
|
|
55
|
-
}
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
58
39
|
/**
|
|
59
40
|
* Safely set a Sentry tag. Silently fails on error.
|
|
60
41
|
*/
|
|
@@ -305,16 +286,32 @@ function createSentrySink() {
|
|
|
305
286
|
* Initialize Sentry with SDK-specific configuration. Idempotent: re-calls
|
|
306
287
|
* only refresh user identity and the cached API-key hash.
|
|
307
288
|
*
|
|
289
|
+
* Breaking change in v9: `appName` moved from the optional fifth parameter
|
|
290
|
+
* to the required third parameter, so every telemetry stream carries an
|
|
291
|
+
* application identity (the `AugustSDK` constructor has required it since
|
|
292
|
+
* v5). Callers on the old positional order get a synchronous validation
|
|
293
|
+
* error rather than silently anonymous events.
|
|
294
|
+
*
|
|
308
295
|
* @param config - Analytics configuration. Pass `tracesSampleRate` to
|
|
309
296
|
* override the default of `0.1`.
|
|
310
297
|
* @param environment - Current environment (DEV or PROD).
|
|
298
|
+
* @param appName - App-name slug, required. Set as the global `app.name`
|
|
299
|
+
* tag on every event and used to derive `partner.id`. Identifier-shaped:
|
|
300
|
+
* 3–64 chars, `[a-zA-Z0-9._-]` only, and not an EVM address — the same
|
|
301
|
+
* rules the `AugustSDK` constructor enforces.
|
|
311
302
|
* @param walletAddress - Optional wallet address for user identification.
|
|
312
303
|
* @param apiKey - Optional API key (hashed for identification).
|
|
313
|
-
* @
|
|
314
|
-
*
|
|
315
|
-
*
|
|
304
|
+
* @throws AugustValidationError (code `INVALID_INPUT`) when `appName` is
|
|
305
|
+
* missing, empty, mis-typed, out of the allowed length range, contains
|
|
306
|
+
* disallowed characters, or is shaped like an EVM address. Thrown before
|
|
307
|
+
* any analytics state mutates, even when analytics would be disabled by
|
|
308
|
+
* config or environment gates.
|
|
316
309
|
*/
|
|
317
|
-
function initializeSentry(config, environment, walletAddress, apiKey
|
|
310
|
+
function initializeSentry(config, environment, appName, walletAddress, apiKey) {
|
|
311
|
+
// Enforce the identity contract before anything else — including the
|
|
312
|
+
// idempotency short-circuit and the disable gates — so a bad appName is
|
|
313
|
+
// equally loud on every call path and in every environment.
|
|
314
|
+
const validatedAppName = (0, app_name_1.validateAppName)(appName);
|
|
318
315
|
// SDK construction runs this multiple times (base + adapter constructors).
|
|
319
316
|
// Short-circuit so the disable-reason logs only once per process.
|
|
320
317
|
if (isInitialized) {
|
|
@@ -358,7 +355,7 @@ function initializeSentry(config, environment, walletAddress, apiKey, appName) {
|
|
|
358
355
|
});
|
|
359
356
|
return;
|
|
360
357
|
}
|
|
361
|
-
if (!forced && isLocalhost()) {
|
|
358
|
+
if (!forced && (0, env_1.isLocalhost)()) {
|
|
362
359
|
isEnabled = false;
|
|
363
360
|
isInitialized = true;
|
|
364
361
|
logger_1.Logger.log.info('analytics.disabled', { reason: 'localhost' });
|
|
@@ -473,11 +470,9 @@ function initializeSentry(config, environment, walletAddress, apiKey, appName) {
|
|
|
473
470
|
safeSetTag('sdk.runtime', (0, sentry_runtime_1.getSentryRuntime)());
|
|
474
471
|
// `app.name` is the dimension we filter on in Sentry to attribute
|
|
475
472
|
// events to a specific consuming application — see SDK quickstart docs.
|
|
476
|
-
|
|
477
|
-
safeSetTag('app.name', appName);
|
|
478
|
-
}
|
|
473
|
+
safeSetTag('app.name', validatedAppName);
|
|
479
474
|
// `unverified:` prefix until the backend API-key → partner-id endpoint exists.
|
|
480
|
-
safeSetTag('partner.id',
|
|
475
|
+
safeSetTag('partner.id', `unverified:${validatedAppName}`);
|
|
481
476
|
safeSetTag('partner.tier', 'unverified');
|
|
482
477
|
// Bridge the SDK's structured logger into Sentry now that the SDK is live.
|
|
483
478
|
// Without this, Logger.log.error/warn are no-ops in production (no
|
package/lib/core/base.class.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { ISolanaConfig, IStellarConfig, IAddress, IChainId, IEnv, IProvider
|
|
|
2
2
|
import { type IAnalyticsConfig } from './analytics';
|
|
3
3
|
import { type IVersionCheckConfig } from './version-check';
|
|
4
4
|
import { type IAttributionConfig } from './attribution';
|
|
5
|
+
import { type ICuratorAlertsConfig } from './logger/curator-alert';
|
|
5
6
|
interface IKeys {
|
|
6
7
|
august?: string;
|
|
7
8
|
graph?: string;
|
|
@@ -10,6 +11,27 @@ interface IKeys {
|
|
|
10
11
|
interface IMonitoring extends IWSMonitorHeaders {
|
|
11
12
|
slackWebhookUrl?: string;
|
|
12
13
|
env?: IEnv;
|
|
14
|
+
/**
|
|
15
|
+
* Curator notifications for failed vault redemptions. Enabled by default
|
|
16
|
+
* (opt-out model, like `analytics`).
|
|
17
|
+
*
|
|
18
|
+
* Stellar vaults are instant-redeem only, so when a redemption fails the
|
|
19
|
+
* vault's curator has no other way to learn about it. The SDK relays the
|
|
20
|
+
* failure to August's notification service, which routes it to that curator's
|
|
21
|
+
* own channel — no credentials or curator identities are held here.
|
|
22
|
+
*
|
|
23
|
+
* Set `enabled: false` (or, in Node, the
|
|
24
|
+
* `AUGUST_SDK_DISABLE_CURATOR_ALERTS` env var) to stop emitting; set
|
|
25
|
+
* `endpoint` only to point a non-prod deployment at a test relay. Nothing is
|
|
26
|
+
* emitted unless `monitoring.env` is `PROD`, `NODE_ENV` is neither
|
|
27
|
+
* `development` nor `test`, and — in a browser, where `NODE_ENV` is not
|
|
28
|
+
* readable — the page is not served from localhost.
|
|
29
|
+
*
|
|
30
|
+
* `enabled: true` is the one exception: it bypasses all three gates, so a
|
|
31
|
+
* `DEV` or test integration that sets it can page a real curator. See
|
|
32
|
+
* {@link ICuratorAlertsConfig}.
|
|
33
|
+
*/
|
|
34
|
+
curatorAlerts?: ICuratorAlertsConfig;
|
|
13
35
|
}
|
|
14
36
|
export interface IAugustBase {
|
|
15
37
|
/**
|
|
@@ -25,7 +47,8 @@ export interface IAugustBase {
|
|
|
25
47
|
* 3–64 characters, `[a-zA-Z0-9._-]` only. Use a slug ("acme-trader"),
|
|
26
48
|
* not a display name ("Acme Trader").
|
|
27
49
|
*
|
|
28
|
-
* @throws
|
|
50
|
+
* @throws AugustValidationError synchronously from the constructor if
|
|
51
|
+
* missing, empty, or malformed.
|
|
29
52
|
*
|
|
30
53
|
* @example
|
|
31
54
|
* ```typescript
|
|
@@ -120,8 +143,8 @@ export declare class AugustBase {
|
|
|
120
143
|
* Initialize base SDK with provider configuration and API keys.
|
|
121
144
|
* Sets up the first provider as the active network by default.
|
|
122
145
|
*
|
|
123
|
-
* @throws
|
|
124
|
-
* length range — see {@link IAugustBase.appName}.
|
|
146
|
+
* @throws AugustValidationError if `appName` is missing, malformed, or
|
|
147
|
+
* out of the allowed length range — see {@link IAugustBase.appName}.
|
|
125
148
|
*/
|
|
126
149
|
constructor({ appName, providers, keys, monitoring, analytics, versionCheck, timeoutMs, publicApiBaseUrl, attribution, }: IAugustBase);
|
|
127
150
|
/**
|
package/lib/core/base.class.js
CHANGED
|
@@ -4,36 +4,11 @@ exports.AugustBase = void 0;
|
|
|
4
4
|
const auth_1 = require("./auth");
|
|
5
5
|
const logger_1 = require("./logger");
|
|
6
6
|
const analytics_1 = require("./analytics");
|
|
7
|
+
const app_name_1 = require("./analytics/app-name");
|
|
7
8
|
const version_check_1 = require("./version-check");
|
|
8
9
|
const fetcher_1 = require("./fetcher");
|
|
9
10
|
const attribution_1 = require("./attribution");
|
|
10
|
-
|
|
11
|
-
* Validate an appName at SDK construction time.
|
|
12
|
-
*
|
|
13
|
-
* Rules (kept intentionally narrow so the value is safe to use as a Sentry
|
|
14
|
-
* tag, an HTTP header value, and a filesystem-safe identifier — this is
|
|
15
|
-
* why we accept slugs only, not display names):
|
|
16
|
-
* - non-empty after trim
|
|
17
|
-
* - 3..64 characters
|
|
18
|
-
* - only `[a-zA-Z0-9._-]`
|
|
19
|
-
*
|
|
20
|
-
* Throws a descriptive Error that names the failed rule and includes a
|
|
21
|
-
* remediation hint pointing at the docs link.
|
|
22
|
-
*/
|
|
23
|
-
function validateAppName(value) {
|
|
24
|
-
const docsHint = 'See https://docs.augustdigital.io/developers/typescript-sdk#app-name';
|
|
25
|
-
if (typeof value !== 'string' || value.trim().length === 0) {
|
|
26
|
-
throw new Error(`August SDK: \`appName\` is required. Pass a stable kebab-case slug identifying your application (e.g. "acme-trader"). ${docsHint}`);
|
|
27
|
-
}
|
|
28
|
-
const trimmed = value.trim();
|
|
29
|
-
if (trimmed.length < 3 || trimmed.length > 64) {
|
|
30
|
-
throw new Error(`August SDK: \`appName\` must be 3-64 characters (got ${trimmed.length}). ${docsHint}`);
|
|
31
|
-
}
|
|
32
|
-
if (!/^[a-zA-Z0-9._-]+$/.test(trimmed)) {
|
|
33
|
-
throw new Error(`August SDK: \`appName\` may only contain letters, digits, '.', '_' and '-' (got "${trimmed}"). Use a slug like "acme-trader", not a display name. ${docsHint}`);
|
|
34
|
-
}
|
|
35
|
-
return trimmed;
|
|
36
|
-
}
|
|
11
|
+
const curator_alert_1 = require("./logger/curator-alert");
|
|
37
12
|
/**
|
|
38
13
|
* Base class providing core SDK functionality including provider management,
|
|
39
14
|
* network switching, and authentication state.
|
|
@@ -53,13 +28,13 @@ class AugustBase {
|
|
|
53
28
|
* Initialize base SDK with provider configuration and API keys.
|
|
54
29
|
* Sets up the first provider as the active network by default.
|
|
55
30
|
*
|
|
56
|
-
* @throws
|
|
57
|
-
* length range — see {@link IAugustBase.appName}.
|
|
31
|
+
* @throws AugustValidationError if `appName` is missing, malformed, or
|
|
32
|
+
* out of the allowed length range — see {@link IAugustBase.appName}.
|
|
58
33
|
*/
|
|
59
34
|
constructor({ appName, providers = {}, keys, monitoring, analytics, versionCheck, timeoutMs, publicApiBaseUrl, attribution, }) {
|
|
60
35
|
// Validate first so the failure mode is a clear, actionable error before
|
|
61
36
|
// any provider / analytics side effects run.
|
|
62
|
-
this.appName = validateAppName(appName);
|
|
37
|
+
this.appName = (0, app_name_1.validateAppName)(appName);
|
|
63
38
|
// TODO: change this to false later when august key is required
|
|
64
39
|
this.authorized = true;
|
|
65
40
|
this.providers = providers;
|
|
@@ -82,7 +57,7 @@ class AugustBase {
|
|
|
82
57
|
logger_1.Logger.setDevMode(environment === 'DEV');
|
|
83
58
|
// Initialize analytics (pass API key for hashed identification + the
|
|
84
59
|
// appName so events can be filtered by consuming application).
|
|
85
|
-
(0, analytics_1.initializeSentry)(analytics ?? { enabled: true }, environment, monitoring?.['x-user-id'], keys?.august
|
|
60
|
+
(0, analytics_1.initializeSentry)(analytics ?? { enabled: true }, environment, this.appName, monitoring?.['x-user-id'], keys?.august);
|
|
86
61
|
// Best-effort version nudge — fire-and-forget, never blocks init, no
|
|
87
62
|
// network call in production. See `core/version-check.ts` for details.
|
|
88
63
|
(0, version_check_1.runVersionCheck)(versionCheck);
|
|
@@ -100,6 +75,16 @@ class AugustBase {
|
|
|
100
75
|
// `publicApiBaseUrl`: called unconditionally so a prior instance's
|
|
101
76
|
// builder codes never leak into a later instance in the same process.
|
|
102
77
|
(0, attribution_1.setAttribution)(attribution ?? null);
|
|
78
|
+
// Same reset-on-omit contract, for the same reason: an instance that says
|
|
79
|
+
// nothing about curator alerts gets the default (on in production), not
|
|
80
|
+
// whatever a previously-constructed instance asked for.
|
|
81
|
+
// Reports follow the API this instance reads from — resolved AFTER
|
|
82
|
+
// `setPublicApiBaseUrl` above, so a staging deployment alerts staging.
|
|
83
|
+
(0, curator_alert_1.configureCuratorAlerts)(monitoring?.curatorAlerts ?? null, {
|
|
84
|
+
appName: this.appName,
|
|
85
|
+
environment: environment,
|
|
86
|
+
apiBaseUrl: (0, fetcher_1.getPublicApiBaseUrl)(),
|
|
87
|
+
});
|
|
103
88
|
}
|
|
104
89
|
/**
|
|
105
90
|
* Verify API keys and authorize SDK usage.
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import type { ChainType, IEnv } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Path on the August public API that accepts a failed-redemption report. Chain
|
|
4
|
+
* lives in the payload, not the path — see {@link IRedeemFailureEvent.chain}.
|
|
5
|
+
*/
|
|
6
|
+
export declare const CURATOR_ALERT_PATH = "/alerts/redeem-failure";
|
|
7
|
+
/**
|
|
8
|
+
* Where a redeem failure is reported: the August public API, which is already
|
|
9
|
+
* this SDK's read origin and already serves browsers.
|
|
10
|
+
*
|
|
11
|
+
* Browser delivery depends on CORS, and the API's allowlist is an enumerated
|
|
12
|
+
* list of partner origins (`ALLOWED_ORIGIN_REGEX` in the backend), not a
|
|
13
|
+
* wildcard. This POST sends `Content-Type: application/json`, so it is
|
|
14
|
+
* preflighted; an integration served from an origin that is not on that list
|
|
15
|
+
* loses every alert at the preflight. Onboarding a curator therefore has two
|
|
16
|
+
* halves — enabling the vault and allowlisting the origin their users load.
|
|
17
|
+
*
|
|
18
|
+
* That service is the trust boundary, not the destination: it validates the
|
|
19
|
+
* report, drops any vault it does not know or that has not opted in,
|
|
20
|
+
* rate-limits per wallet and per vault, and only then forwards to the Telegram
|
|
21
|
+
* bot that holds the token and the curator's channel. Nothing
|
|
22
|
+
* credential-shaped ships in this bundle, which is also why this endpoint
|
|
23
|
+
* takes no API key — a key in a browser bundle is a published key
|
|
24
|
+
* (CLAUDE.md §5). See {@link reportRedeemFailure} for the trust model.
|
|
25
|
+
*/
|
|
26
|
+
export declare const DEFAULT_CURATOR_ALERT_ENDPOINT: string;
|
|
27
|
+
/** Env equivalent of `monitoring.curatorAlerts.enabled: false`. Node only. */
|
|
28
|
+
export declare const CURATOR_ALERTS_DISABLE_ENV_VAR = "AUGUST_SDK_DISABLE_CURATOR_ALERTS";
|
|
29
|
+
/** Curator-alert reporting. Enabled by default; this is the opt-out. */
|
|
30
|
+
export interface ICuratorAlertsConfig {
|
|
31
|
+
/**
|
|
32
|
+
* `false` stops emitting entirely. `true` forces emitting even in an
|
|
33
|
+
* environment the SDK would otherwise stay quiet in — it bypasses **every**
|
|
34
|
+
* environment gate: `NODE_ENV` of `development`/`test`, a browser served
|
|
35
|
+
* from a loopback or private host, and `monitoring.env` other than `PROD`.
|
|
36
|
+
* It does NOT lift the mainnet-only restriction; only `endpoint` does. A
|
|
37
|
+
* `DEV` or test
|
|
38
|
+
* integration that sets it and then fails a mainnet redeem pages a real
|
|
39
|
+
* curator, so use it only when deliberately exercising the path (pair it
|
|
40
|
+
* with `endpoint` to aim at a test relay). The only thing that still wins is
|
|
41
|
+
* the {@link CURATOR_ALERTS_DISABLE_ENV_VAR} kill switch.
|
|
42
|
+
*/
|
|
43
|
+
enabled?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Override the relay endpoint. Defaults to
|
|
46
|
+
* {@link DEFAULT_CURATOR_ALERT_ENDPOINT}. Setting it also lifts the
|
|
47
|
+
* mainnet-only restriction, so a staging relay can receive testnet failures.
|
|
48
|
+
*/
|
|
49
|
+
endpoint?: string;
|
|
50
|
+
}
|
|
51
|
+
/** Fields every report carries, whatever stage the redemption failed at. */
|
|
52
|
+
interface IRedeemFailureBase {
|
|
53
|
+
/**
|
|
54
|
+
* Chain family the vault lives on. Carried rather than assumed so the
|
|
55
|
+
* receiving endpoint stays one contract for every chain; it decides which
|
|
56
|
+
* families it actually serves, and validates the identifiers below by that
|
|
57
|
+
* family's rules.
|
|
58
|
+
*/
|
|
59
|
+
chain: ChainType;
|
|
60
|
+
/**
|
|
61
|
+
* Network within the family, in that family's own vocabulary — Stellar's
|
|
62
|
+
* `mainnet`/`testnet`, Solana's `mainnet-beta`, an EVM network name. A plain
|
|
63
|
+
* string rather than one family's union, because the receiving endpoint
|
|
64
|
+
* validates it against the family named in `chain`; typing it as Stellar's
|
|
65
|
+
* two values would make this the narrower half of a contract the rest of this
|
|
66
|
+
* module describes as chain-agnostic.
|
|
67
|
+
*/
|
|
68
|
+
network: string;
|
|
69
|
+
/** Vault identifier in the chain's own format. The endpoint routes on this. */
|
|
70
|
+
contractId: string;
|
|
71
|
+
/** Account that attempted the redemption, in the chain's own format. */
|
|
72
|
+
eoa: string;
|
|
73
|
+
/** Shares requested, in the vault's smallest unit (unscaled). */
|
|
74
|
+
sharesRaw: string;
|
|
75
|
+
/** Failure detail; sanitized and capped before it leaves the process. */
|
|
76
|
+
error: string;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* A redemption the vault refused before anything reached chain — a failed
|
|
80
|
+
* simulation, or a vault whose ledger state needs restoring. There is no
|
|
81
|
+
* on-chain artifact, so the receiving endpoint has nothing to verify the claim
|
|
82
|
+
* against and treats it as the weaker of the two. Which build stage raised it
|
|
83
|
+
* stays legible in `error`.
|
|
84
|
+
*/
|
|
85
|
+
interface IRedeemBuildFailure extends IRedeemFailureBase {
|
|
86
|
+
phase: 'simulation';
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* A redemption that executed on chain and failed. `txHash` is what makes this
|
|
90
|
+
* the stronger claim — the endpoint can verify it — so it is required here
|
|
91
|
+
* rather than optional, which is the whole reason these are two types.
|
|
92
|
+
*/
|
|
93
|
+
interface IRedeemSubmissionFailure extends IRedeemFailureBase {
|
|
94
|
+
phase: 'submission';
|
|
95
|
+
/** The failed transaction. Verifiable, which is why it is not optional. */
|
|
96
|
+
txHash: string;
|
|
97
|
+
/** Transaction result code, when the result XDR decoded. */
|
|
98
|
+
resultCode?: string;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* A redemption failure worth a curator's attention.
|
|
102
|
+
*
|
|
103
|
+
* Two members rather than one shape with optional fields, because `txHash` is
|
|
104
|
+
* only meaningful — and is always available — on the submission path. As a
|
|
105
|
+
* single interface, `{ phase: 'simulation', txHash }` and a submission report
|
|
106
|
+
* with no hash both type-checked, and the receiving endpoint's `is_well_formed`
|
|
107
|
+
* check was the only thing between either and a silently dropped alert. That
|
|
108
|
+
* check stays, since a server cannot trust its input, but it is no longer
|
|
109
|
+
* covering for a shape this SDK could have made unrepresentable. The two call
|
|
110
|
+
* sites in `adapters/stellar/` are the ones this actually constrains, and they
|
|
111
|
+
* are type-checked by `pnpm build`.
|
|
112
|
+
*
|
|
113
|
+
* @internal
|
|
114
|
+
*/
|
|
115
|
+
export type IRedeemFailureEvent = IRedeemBuildFailure | IRedeemSubmissionFailure;
|
|
116
|
+
/** Ambient facts about the reporting SDK instance, supplied by `AugustBase`. */
|
|
117
|
+
export interface ICuratorAlertsContext {
|
|
118
|
+
/** Carried on the payload so August can tell partner traffic apart. */
|
|
119
|
+
appName?: string;
|
|
120
|
+
/**
|
|
121
|
+
* `monitoring.env`. Anything other than `'PROD'` keeps the SDK quiet unless
|
|
122
|
+
* `config.enabled` is explicitly `true`.
|
|
123
|
+
*/
|
|
124
|
+
environment?: IEnv;
|
|
125
|
+
/**
|
|
126
|
+
* Effective base URL of the August public API. Reports follow the API this
|
|
127
|
+
* instance reads from, so a deployment pointed at a staging backend alerts
|
|
128
|
+
* staging rather than production.
|
|
129
|
+
*/
|
|
130
|
+
apiBaseUrl?: string;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Apply constructor config. Called unconditionally by `AugustBase` so an
|
|
134
|
+
* instance that omits `curatorAlerts` RESETS to the defaults rather than
|
|
135
|
+
* inheriting a prior instance's settings — same contract as
|
|
136
|
+
* `setPublicApiBaseUrl` and `setAttribution`.
|
|
137
|
+
*
|
|
138
|
+
* Also the supported opt-out for code that calls the `Stellar` namespace
|
|
139
|
+
* functions directly without constructing an `AugustSDK` (the testnet flow in
|
|
140
|
+
* the docs), and the only one that works in a browser, where the env var is
|
|
141
|
+
* unreadable.
|
|
142
|
+
*
|
|
143
|
+
* @param config - `monitoring.curatorAlerts`, or `null` to restore defaults.
|
|
144
|
+
* @param context - Facts about the reporting instance; omitted entirely by a
|
|
145
|
+
* caller that only wants to disable reporting.
|
|
146
|
+
*/
|
|
147
|
+
export declare function configureCuratorAlerts(config: ICuratorAlertsConfig | null, context?: ICuratorAlertsContext): void;
|
|
148
|
+
/**
|
|
149
|
+
* Drop every suppression key. Test-only seam — reconfiguration no longer
|
|
150
|
+
* clears the window on its own when the configuration is unchanged, so a suite
|
|
151
|
+
* that reports the same failure across cases needs an explicit reset.
|
|
152
|
+
* @internal
|
|
153
|
+
*/
|
|
154
|
+
export declare function resetCuratorAlertDedupe(): void;
|
|
155
|
+
/**
|
|
156
|
+
* Whether an alert would be sent right now.
|
|
157
|
+
*
|
|
158
|
+
* Quiet by default outside production, mirroring `analytics`: a partner's Jest
|
|
159
|
+
* suite or `next dev` session exercising a failing redeem must not page a real
|
|
160
|
+
* curator. Two gates are needed for that, because they cover different
|
|
161
|
+
* runtimes — `NODE_ENV` is the Node one, and bundlers strip or stub
|
|
162
|
+
* `process.env` in the browser, so a locally-served app is recognised by its
|
|
163
|
+
* hostname instead (CLAUDE.md §5). Without that gate, a browser app run
|
|
164
|
+
* against mainnet from any loopback or private origin — `localhost`, a
|
|
165
|
+
* container on `172.20.0.0/16`, `[::1]` — pages a real curator on every
|
|
166
|
+
* failed redeem. `isLocalhost` in `core/analytics/env` lists the ranges.
|
|
167
|
+
*
|
|
168
|
+
* `enabled: true` overrides both — it is the documented way to exercise the
|
|
169
|
+
* path deliberately, and the SDK's own suite relies on it.
|
|
170
|
+
*
|
|
171
|
+
* The env var is read per call (not once at module load) so a consumer that
|
|
172
|
+
* sets it after import is still honoured, and a test can set and unset it
|
|
173
|
+
* without re-importing. It deliberately outranks an explicit `enabled: true`:
|
|
174
|
+
* it is the kill switch, and an operator setting it should not have to find
|
|
175
|
+
* and edit the construction site to be obeyed.
|
|
176
|
+
*/
|
|
177
|
+
export declare function areCuratorAlertsEnabled(): boolean;
|
|
178
|
+
/**
|
|
179
|
+
* Report a failed vault redemption for the curator of that vault.
|
|
180
|
+
*
|
|
181
|
+
* **Why this exists.** Stellar vaults are instant-redeem only — there is no
|
|
182
|
+
* request/queue path — so a curator whose users' redemptions are failing has
|
|
183
|
+
* no signal at all today: the failure surfaces to the user, and to August's
|
|
184
|
+
* internal Sentry, and stops there. Emitting from the SDK rather than from a
|
|
185
|
+
* single frontend means any integration can report one (AUGUST-7162) — subject
|
|
186
|
+
* to the CORS caveat on {@link DEFAULT_CURATOR_ALERT_ENDPOINT}.
|
|
187
|
+
*
|
|
188
|
+
* **Trust model.** The endpoint is public by construction — it ships in this
|
|
189
|
+
* bundle — so the relay treats every event as untrusted input, not as an
|
|
190
|
+
* attested fact. The SDK's job is to report accurately; the relay's job is to
|
|
191
|
+
* verify, rate-limit per `{vault, wallet}`, and drop events naming a vault
|
|
192
|
+
* outside its routing map. `'submission'` events carry a `txHash` the relay can
|
|
193
|
+
* confirm on chain, which makes them unforgeable; `'simulation'` events have no
|
|
194
|
+
* on-chain artifact and are treated as the weaker claim. Nothing
|
|
195
|
+
* credential-shaped is reachable from here: no bot token, no chat id, no
|
|
196
|
+
* curator identity.
|
|
197
|
+
*
|
|
198
|
+
* **Side effects.** At most one `POST` to the relay, fire-and-forget: this runs
|
|
199
|
+
* inside a `catch` on a money path, so it never awaits, never throws back into
|
|
200
|
+
* the caller, and never alters the error the caller sees. Suppressed to one
|
|
201
|
+
* send per `{contractId, eoa, phase, resultCode, error class}` per 10 minutes,
|
|
202
|
+
* so a wallet retrying a deterministic failure costs a single request. Note the
|
|
203
|
+
* receiving service applies its own, coarser window on top. A no-op when
|
|
204
|
+
* reporting is disabled (see {@link areCuratorAlertsEnabled}) and, unless a
|
|
205
|
+
* custom endpoint is configured, for any network other than mainnet — a
|
|
206
|
+
* testnet failure is not a curator's problem.
|
|
207
|
+
*
|
|
208
|
+
* @param event - The failed attempt. `error` is sanitized (secrets scrubbed via
|
|
209
|
+
* `sanitizeString`) and capped at 1500 characters before it leaves the
|
|
210
|
+
* process; `sharesRaw` is relayed unscaled, and the receiving service scales
|
|
211
|
+
* it for display with the decimals it holds for that vault — which for an
|
|
212
|
+
* offset vault are the asset's, not the share token's, so the figure a curator
|
|
213
|
+
* sees is a magnitude rather than an exact amount (see AUGUST-6381).
|
|
214
|
+
* @internal
|
|
215
|
+
*/
|
|
216
|
+
export declare function reportRedeemFailure(event: IRedeemFailureEvent): void;
|
|
217
|
+
export {};
|