@secondlayer/shared 13.8.0 → 13.9.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/dist/src/archive/range-digest.d.ts +5 -0
- package/dist/src/archive/semantic-digest-builder.d.ts +5 -0
- package/dist/src/coverage/index.d.ts +5 -0
- package/dist/src/db/index.d.ts +5 -0
- package/dist/src/db/queries/chain-reorgs.d.ts +5 -0
- package/dist/src/db/queries/contracts.d.ts +5 -0
- package/dist/src/db/queries/instance.d.ts +5 -0
- package/dist/src/db/queries/integrity.d.ts +5 -0
- package/dist/src/db/queries/subgraph-gaps.d.ts +5 -0
- package/dist/src/db/queries/subgraph-operations.d.ts +5 -0
- package/dist/src/db/queries/subgraphs.d.ts +5 -0
- package/dist/src/db/queries/sync-scope.d.ts +5 -0
- package/dist/src/db/queries/webhooks.d.ts +5 -0
- package/dist/src/db/schema.d.ts +5 -0
- package/dist/src/error-envelope.d.ts +1 -0
- package/dist/src/error-envelope.js.map +2 -2
- package/dist/src/errors.d.ts +7 -1
- package/dist/src/errors.js +12 -1
- package/dist/src/errors.js.map +3 -3
- package/dist/src/index.d.ts +12 -1
- package/dist/src/index.js +12 -1
- package/dist/src/index.js.map +3 -3
- package/dist/src/insights/index.d.ts +13 -2
- package/dist/src/insights/index.js +15 -7
- package/dist/src/insights/index.js.map +4 -4
- package/dist/src/insights/thresholds.d.ts +6 -1
- package/dist/src/insights/thresholds.js +5 -1
- package/dist/src/insights/thresholds.js.map +3 -3
- package/dist/src/node/local-client.d.ts +5 -0
- package/migrations/0174_internal_accounts.ts +21 -0
- package/migrations/0175_failed_request_key_id.ts +23 -0
- package/package.json +1 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/insights/thresholds.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"// Detector thresholds. Named constants, not config. Tune from real data;\n// until then these stay conservative: a wrong insight costs more trust than\n// a missed one.\n//\n// This file must stay import-free. The SDK's webhook doctor imports it, and\n// the doctor reaches the browser through apps/web, so anything imported here\n// would ship to the client bundle.\n//\n// Constants computed from an expression carry an explicit `: number`: the\n// bundled `.d.ts` otherwise types them `unknown`.\n\n// ── Webhook doctor (shared with the SDK / `sl webhooks doctor`) ────────\nexport const RATE_LIMITED_MIN_ATTEMPTS = 10;\nexport const RATE_LIMITED_MIN_RATIO = 0.5;\nexport const DOWN_MIN_CONSECUTIVE = 5;\nexport const REJECTS_MIN_CONSECUTIVE = 5;\nexport const SLOW_WINDOW = 20;\nexport const SLOW_MIN_SAMPLES = 5;\nexport const SLOW_TIMEOUT_RATIO = 0.5;\nexport const LAG_WINDOW = 20;\nexport const LAG_MIN_SAMPLES = 5;\nexport const LAG_THRESHOLD_MS = 60_000;\n\n// ── Tenant rules ───────────────────────────────────────────────────────\n/** Consecutive newest 2xx HTML responses that mean a login wall. */\nexport const LOGIN_WALL_MIN_CONSECUTIVE = 20;\n/** Share of prior-week 2xx responses that must have been JSON. */\nexport const LOGIN_WALL_PRIOR_JSON_RATIO = 0.8;\n/** Prior-week successful responses needed before a baseline counts. */\nexport const LOGIN_WALL_MIN_PRIOR = 10;\nexport const SLOWING_DAYS = 14;\nexport const SLOWING_MIN_RISING_DAYS = 10;\nexport const SLOWING_MIN_R2 = 0.8;\nexport const TLS_WARN_DAYS = 14;\n/** Dead outbox rows are deleted at 90 days; warn at 83. */\nexport const DEAD_LETTER_WARN_AGE_DAYS = 83;\nexport const DEAD_LETTER_DELETE_AGE_DAYS = 90;\nexport const TEST_ENDPOINT_MIN_AGE_DAYS = 7;\nexport const HANDLER_ERRORS_MIN_24H = 10;\n/** Blocks behind tip, for 3 consecutive snapshots. */\nexport const SUBGRAPH_LAG_BLOCKS = 20;\nexport const SUBGRAPH_LAG_SNAPSHOTS = 3;\nexport const SUBGRAPH_LAG_LOSING_BLOCKS = 500;\n\n// ── Platform rules ─────────────────────────────────────────────────────\n/**\n * Index and Streams cap one page at 1000 rows\n * (`packages/api/src/index/_shared.ts` `Math.min(1000, parsed)`,\n * `packages/api/src/routes/streams.ts` `limit: Math.min(1000, limit)`).\n */\nexport const PAGE_CAP_ROWS = 1000;\nexport const DUPLICATE_READS_MIN_PAGES = 3;\nexport const DUPLICATE_READS_WINDOW_MS = 3_600_000;\n/** Only repeats that started within this long ago count as current. */\nexport const DUPLICATE_READS_LOOKBACK_MS: number = 24 * 3_600_000;\nexport const POLLING_MIN_DURATION_MS = 3_600_000;\n/** Requests needed in the window before an interval means anything. */\nexport const POLLING_MIN_REQUESTS = 5;\nexport const POLLING_LOOKBACK_MS: number = 6 * 3_600_000;\nexport const POLLING_MAX_STDDEV_RATIO = 0.2;\nexport const POLLING_MIN_EMPTY_RATIO = 0.8;\nexport const SERVER_ERRORS_MIN_5XX = 3;\nexport const BACKFILL_DAY_SHARE = 0.25;\nexport const BACKFILL_FULL_PAGE_RATIO = 0.9;\n/** A day under this many rows is never called a backfill, however full its pages. */\nexport const BACKFILL_MIN_DAY_ROWS = 100_000;\nexport const CREDITS_RUNWAY_WARN_DAYS = 7;\n/** An account key idle this many days (or unused since creation) is flagged. */\nexport const KEY_UNUSED_DAYS = 30;\n\n// ── Lifecycle ──────────────────────────────────────────────────────────\n/** A resolved insight stays visible as \"recovered\" for this long. */\nexport const RECOVERED_VISIBLE_MS: number = 24 * 3600_000;\n/** Consecutive clean evaluations before an open insight resolves. */\nexport const CLEAR_STREAK_TO_RESOLVE = 2;\n"
|
|
5
|
+
"// Detector thresholds. Named constants, not config. Tune from real data;\n// until then these stay conservative: a wrong insight costs more trust than\n// a missed one.\n//\n// This file must stay import-free. The SDK's webhook doctor imports it, and\n// the doctor reaches the browser through apps/web, so anything imported here\n// would ship to the client bundle.\n//\n// Constants computed from an expression carry an explicit `: number`: the\n// bundled `.d.ts` otherwise types them `unknown`.\n\n// ── Webhook doctor (shared with the SDK / `sl webhooks doctor`) ────────\nexport const RATE_LIMITED_MIN_ATTEMPTS = 10;\nexport const RATE_LIMITED_MIN_RATIO = 0.5;\nexport const DOWN_MIN_CONSECUTIVE = 5;\nexport const REJECTS_MIN_CONSECUTIVE = 5;\nexport const SLOW_WINDOW = 20;\nexport const SLOW_MIN_SAMPLES = 5;\nexport const SLOW_TIMEOUT_RATIO = 0.5;\nexport const LAG_WINDOW = 20;\nexport const LAG_MIN_SAMPLES = 5;\nexport const LAG_THRESHOLD_MS = 60_000;\n\n// ── Tenant rules ───────────────────────────────────────────────────────\n/** Consecutive newest 2xx HTML responses that mean a login wall. */\nexport const LOGIN_WALL_MIN_CONSECUTIVE = 20;\n/** Share of prior-week 2xx responses that must have been JSON. */\nexport const LOGIN_WALL_PRIOR_JSON_RATIO = 0.8;\n/** Prior-week successful responses needed before a baseline counts. */\nexport const LOGIN_WALL_MIN_PRIOR = 10;\nexport const SLOWING_DAYS = 14;\nexport const SLOWING_MIN_RISING_DAYS = 10;\nexport const SLOWING_MIN_R2 = 0.8;\nexport const TLS_WARN_DAYS = 14;\n/** Dead outbox rows are deleted at 90 days; warn at 83. */\nexport const DEAD_LETTER_WARN_AGE_DAYS = 83;\nexport const DEAD_LETTER_DELETE_AGE_DAYS = 90;\nexport const TEST_ENDPOINT_MIN_AGE_DAYS = 7;\nexport const HANDLER_ERRORS_MIN_24H = 10;\n/** Blocks behind tip, for 3 consecutive snapshots. */\nexport const SUBGRAPH_LAG_BLOCKS = 20;\nexport const SUBGRAPH_LAG_SNAPSHOTS = 3;\nexport const SUBGRAPH_LAG_LOSING_BLOCKS = 500;\n\n// ── Platform rules ─────────────────────────────────────────────────────\n/**\n * Index and Streams cap one page at 1000 rows\n * (`packages/api/src/index/_shared.ts` `Math.min(1000, parsed)`,\n * `packages/api/src/routes/streams.ts` `limit: Math.min(1000, limit)`).\n */\nexport const PAGE_CAP_ROWS = 1000;\nexport const DUPLICATE_READS_MIN_PAGES = 3;\nexport const DUPLICATE_READS_WINDOW_MS = 3_600_000;\n/** Only repeats that started within this long ago count as current. */\nexport const DUPLICATE_READS_LOOKBACK_MS: number = 24 * 3_600_000;\nexport const POLLING_MIN_DURATION_MS = 3_600_000;\n/** Requests needed in the window before an interval means anything. */\nexport const POLLING_MIN_REQUESTS = 5;\nexport const POLLING_LOOKBACK_MS: number = 6 * 3_600_000;\nexport const POLLING_MAX_STDDEV_RATIO = 0.2;\n/** A request this soon after the previous one is a cursor-follow page of the same poll. */\nexport const POLLING_FOLLOW_GAP_MS = 10_000;\nexport const POLLING_MIN_EMPTY_RATIO = 0.8;\nexport const SERVER_ERRORS_MIN_5XX = 3;\nexport const BACKFILL_DAY_SHARE = 0.25;\nexport const BACKFILL_FULL_PAGE_RATIO = 0.9;\n/** A day under this many rows is never called a backfill, however full its pages. */\nexport const BACKFILL_MIN_DAY_ROWS = 100_000;\nexport const CREDITS_RUNWAY_WARN_DAYS = 7;\n/** An account key idle this many days (or unused since creation) is flagged. */\nexport const KEY_UNUSED_DAYS = 30;\n/** A revoked key called within this long is still in use; older calls only\n * count toward the 24h evidence, so the insight clears once calls stop. */\nexport const REVOKED_KEY_ACTIVE_MS = 3_600_000;\n\n// ── Lifecycle ──────────────────────────────────────────────────────────\n/** A resolved insight stays visible as \"recovered\" for this long. */\nexport const RECOVERED_VISIBLE_MS: number = 24 * 3600_000;\n/** Consecutive clean evaluations before an open insight resolves. */\nexport const CLEAR_STREAK_TO_RESOLVE = 2;\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";AAYO,IAAM,4BAA4B;AAClC,IAAM,yBAAyB;AAC/B,IAAM,uBAAuB;AAC7B,IAAM,0BAA0B;AAChC,IAAM,cAAc;AACpB,IAAM,mBAAmB;AACzB,IAAM,qBAAqB;AAC3B,IAAM,aAAa;AACnB,IAAM,kBAAkB;AACxB,IAAM,mBAAmB;AAIzB,IAAM,6BAA6B;AAEnC,IAAM,8BAA8B;AAEpC,IAAM,uBAAuB;AAC7B,IAAM,eAAe;AACrB,IAAM,0BAA0B;AAChC,IAAM,iBAAiB;AACvB,IAAM,gBAAgB;AAEtB,IAAM,4BAA4B;AAClC,IAAM,8BAA8B;AACpC,IAAM,6BAA6B;AACnC,IAAM,yBAAyB;AAE/B,IAAM,sBAAsB;AAC5B,IAAM,yBAAyB;AAC/B,IAAM,6BAA6B;AAQnC,IAAM,gBAAgB;AACtB,IAAM,4BAA4B;AAClC,IAAM,4BAA4B;AAElC,IAAM,8BAAsC,KAAK;AACjD,IAAM,0BAA0B;AAEhC,IAAM,uBAAuB;AAC7B,IAAM,sBAA8B,IAAI;AACxC,IAAM,2BAA2B;
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": ";AAYO,IAAM,4BAA4B;AAClC,IAAM,yBAAyB;AAC/B,IAAM,uBAAuB;AAC7B,IAAM,0BAA0B;AAChC,IAAM,cAAc;AACpB,IAAM,mBAAmB;AACzB,IAAM,qBAAqB;AAC3B,IAAM,aAAa;AACnB,IAAM,kBAAkB;AACxB,IAAM,mBAAmB;AAIzB,IAAM,6BAA6B;AAEnC,IAAM,8BAA8B;AAEpC,IAAM,uBAAuB;AAC7B,IAAM,eAAe;AACrB,IAAM,0BAA0B;AAChC,IAAM,iBAAiB;AACvB,IAAM,gBAAgB;AAEtB,IAAM,4BAA4B;AAClC,IAAM,8BAA8B;AACpC,IAAM,6BAA6B;AACnC,IAAM,yBAAyB;AAE/B,IAAM,sBAAsB;AAC5B,IAAM,yBAAyB;AAC/B,IAAM,6BAA6B;AAQnC,IAAM,gBAAgB;AACtB,IAAM,4BAA4B;AAClC,IAAM,4BAA4B;AAElC,IAAM,8BAAsC,KAAK;AACjD,IAAM,0BAA0B;AAEhC,IAAM,uBAAuB;AAC7B,IAAM,sBAA8B,IAAI;AACxC,IAAM,2BAA2B;AAEjC,IAAM,wBAAwB;AAC9B,IAAM,0BAA0B;AAChC,IAAM,wBAAwB;AAC9B,IAAM,qBAAqB;AAC3B,IAAM,2BAA2B;AAEjC,IAAM,wBAAwB;AAC9B,IAAM,2BAA2B;AAEjC,IAAM,kBAAkB;AAGxB,IAAM,wBAAwB;AAI9B,IAAM,uBAA+B,KAAK;AAE1C,IAAM,0BAA0B;",
|
|
8
|
+
"debugId": "C74533CBF9BC87AC64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -306,6 +306,9 @@ interface AccountsTable {
|
|
|
306
306
|
email: string | null;
|
|
307
307
|
/** True for anonymous self-serve accounts until claimed via magic link. */
|
|
308
308
|
ghost: Generated<boolean>;
|
|
309
|
+
/** First-party service account: usage priced at $0, never gated on
|
|
310
|
+
* credits. Set by ops only. */
|
|
311
|
+
internal: Generated<boolean>;
|
|
309
312
|
/** Stacks principal owning a wallet-ghost account. */
|
|
310
313
|
wallet_principal: string | null;
|
|
311
314
|
display_name: string | null;
|
|
@@ -1196,6 +1199,8 @@ interface ApiFailedRequestsTable {
|
|
|
1196
1199
|
message: Generated<string>;
|
|
1197
1200
|
query: Record<string, unknown>;
|
|
1198
1201
|
origin: string | null;
|
|
1202
|
+
/** Revoked account key the request presented (`KEY_REVOKED` only). */
|
|
1203
|
+
api_key_id: string | null;
|
|
1199
1204
|
created_at: Generated<Date>;
|
|
1200
1205
|
}
|
|
1201
1206
|
/**
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type Kysely, sql } from "kysely";
|
|
2
|
+
import { onControlPlane } from "../src/db/migration-role.ts";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* First-party accounts (Sentinel's service account): usage is still written
|
|
6
|
+
* to `usage_ledger`, priced at $0, and no balance, floor or cap ever stops
|
|
7
|
+
* them. Set by ops only; no route writes it.
|
|
8
|
+
*/
|
|
9
|
+
export async function up(db: Kysely<unknown>): Promise<void> {
|
|
10
|
+
await onControlPlane(async () => {
|
|
11
|
+
await sql`
|
|
12
|
+
ALTER TABLE accounts ADD COLUMN IF NOT EXISTS internal boolean NOT NULL DEFAULT false
|
|
13
|
+
`.execute(db);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function down(db: Kysely<unknown>): Promise<void> {
|
|
18
|
+
await onControlPlane(async () => {
|
|
19
|
+
await sql`ALTER TABLE accounts DROP COLUMN IF EXISTS internal`.execute(db);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type Kysely, sql } from "kysely";
|
|
2
|
+
import { onControlPlane } from "../src/db/migration-role.ts";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The key a failed request presented, when there was one we know: today only
|
|
6
|
+
* a revoked account key (`KEY_REVOKED`), so the account can see which revoked
|
|
7
|
+
* key is still being called. Nullable, no FK: rows live 24h.
|
|
8
|
+
*/
|
|
9
|
+
export async function up(db: Kysely<unknown>): Promise<void> {
|
|
10
|
+
await onControlPlane(async () => {
|
|
11
|
+
await sql`
|
|
12
|
+
ALTER TABLE api_failed_requests ADD COLUMN IF NOT EXISTS api_key_id uuid
|
|
13
|
+
`.execute(db);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function down(db: Kysely<unknown>): Promise<void> {
|
|
18
|
+
await onControlPlane(async () => {
|
|
19
|
+
await sql`ALTER TABLE api_failed_requests DROP COLUMN IF EXISTS api_key_id`.execute(
|
|
20
|
+
db,
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
}
|