@pdfvector/util 0.5.1 → 0.6.1

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.
@@ -1,5 +1,6 @@
1
1
  export * from "./free.js";
2
2
  export * from "./overview.js";
3
3
  export * from "./provider-costs.js";
4
+ export * from "./provider-health.js";
4
5
  export * from "./records.js";
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../lib/contract/gateway/router/admin/usage/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../lib/contract/gateway/router/admin/usage/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC"}
@@ -1,4 +1,5 @@
1
1
  export * from "./free.js";
2
2
  export * from "./overview.js";
3
3
  export * from "./provider-costs.js";
4
+ export * from "./provider-health.js";
4
5
  export * from "./records.js";
@@ -0,0 +1,44 @@
1
+ import * as z from "zod";
2
+ /** Failure and hidden-fallback rates per provider/service for the admin console. */
3
+ export declare const getProviderHealth: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<z.ZodDefault<z.ZodOptional<z.ZodObject<{
4
+ instanceId: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
5
+ }, z.core.$strip>>>, z.ZodObject<{
6
+ generatedAt: z.ZodString;
7
+ thresholds: z.ZodObject<{
8
+ downMinCalls1h: z.ZodNumber;
9
+ degradedMinCalls24h: z.ZodNumber;
10
+ degradedFailureRate24h: z.ZodNumber;
11
+ }, z.core.$strip>;
12
+ rows: z.ZodArray<z.ZodObject<{
13
+ provider: z.ZodString;
14
+ service: z.ZodString;
15
+ status: z.ZodEnum<{
16
+ degraded: "degraded";
17
+ down: "down";
18
+ ok: "ok";
19
+ }>;
20
+ windows: z.ZodObject<{
21
+ "1h": z.ZodObject<{
22
+ calls: z.ZodNumber;
23
+ systemErrors: z.ZodNumber;
24
+ userErrors: z.ZodNumber;
25
+ fallbacks: z.ZodNumber;
26
+ }, z.core.$strip>;
27
+ "24h": z.ZodObject<{
28
+ calls: z.ZodNumber;
29
+ systemErrors: z.ZodNumber;
30
+ userErrors: z.ZodNumber;
31
+ fallbacks: z.ZodNumber;
32
+ }, z.core.$strip>;
33
+ "7d": z.ZodObject<{
34
+ calls: z.ZodNumber;
35
+ systemErrors: z.ZodNumber;
36
+ userErrors: z.ZodNumber;
37
+ fallbacks: z.ZodNumber;
38
+ }, z.core.$strip>;
39
+ }, z.core.$strip>;
40
+ lastError: z.ZodNullable<z.ZodString>;
41
+ lastErrorAt: z.ZodNullable<z.ZodString>;
42
+ }, z.core.$strip>>;
43
+ }, z.core.$strip>, Record<never, never>, Record<never, never>>;
44
+ //# sourceMappingURL=provider-health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-health.d.ts","sourceRoot":"","sources":["../../../../../../../lib/contract/gateway/router/admin/usage/provider-health.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAWzB,oFAAoF;AACpF,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8DA8B5B,CAAC"}
@@ -0,0 +1,35 @@
1
+ import { oc } from "@orpc/contract";
2
+ import * as z from "zod";
3
+ const windowSchema = z.object({
4
+ calls: z.number(),
5
+ systemErrors: z.number(),
6
+ userErrors: z.number(),
7
+ fallbacks: z.number(),
8
+ });
9
+ const providerHealthStatuses = ["down", "degraded", "ok"];
10
+ /** Failure and hidden-fallback rates per provider/service for the admin console. */
11
+ export const getProviderHealth = oc
12
+ .input(z
13
+ .object({ instanceId: z.number().nullable().optional() })
14
+ .optional()
15
+ .default({}))
16
+ .output(z.object({
17
+ generatedAt: z.string(),
18
+ thresholds: z.object({
19
+ downMinCalls1h: z.number(),
20
+ degradedMinCalls24h: z.number(),
21
+ degradedFailureRate24h: z.number(),
22
+ }),
23
+ rows: z.array(z.object({
24
+ provider: z.string(),
25
+ service: z.string(),
26
+ status: z.enum(providerHealthStatuses),
27
+ windows: z.object({
28
+ "1h": windowSchema,
29
+ "24h": windowSchema,
30
+ "7d": windowSchema,
31
+ }),
32
+ lastError: z.string().nullable(),
33
+ lastErrorAt: z.string().nullable(),
34
+ })),
35
+ }));
@@ -1 +1 @@
1
- {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../../../../lib/contract/instance/router/academic/search.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA2DxB,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8DAkHhB,CAAC"}
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../../../../lib/contract/instance/router/academic/search.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA2DxB,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8DAyHhB,CAAC"}
@@ -133,7 +133,12 @@ export const search = oc
133
133
  .output(z.object({
134
134
  estimatedTotalResults: z.number(),
135
135
  results: z.array(publicationSchema),
136
- errors: z.array(providerErrorSchema).nullish(),
136
+ errors: z
137
+ .array(providerErrorSchema)
138
+ .nullish()
139
+ .describe("Providers that failed for this request (for example rate limited or unavailable). " +
140
+ "When present, `results` only contain papers from the providers that succeeded, so treat the response as partial. " +
141
+ "Credits are the same either way."),
137
142
  requestId: z.number().int(),
138
143
  }))
139
144
  .route({
@@ -6,10 +6,12 @@ export * from "./environment.js";
6
6
  export * from "./format.js";
7
7
  export * from "./free-tier.js";
8
8
  export * from "./get-error-message.js";
9
+ export * from "./is-abort-error.js";
9
10
  export * from "./plan.js";
10
11
  export * from "./ports.js";
11
12
  export * from "./product-title.js";
12
13
  export * from "./sentry-distribution.js";
14
+ export * from "./sentry-event-limiter.js";
13
15
  export * from "./sentry-release.js";
14
16
  export * from "./service-logger.js";
15
17
  export * from "./tier.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,QAAQ,CAAC;AACvB,cAAc,sCAAsC,CAAC;AACrD,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,QAAQ,CAAC;AACvB,cAAc,sCAAsC,CAAC;AACrD,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC"}
package/.tsc/lib/index.js CHANGED
@@ -6,10 +6,12 @@ export * from "./environment.js";
6
6
  export * from "./format.js";
7
7
  export * from "./free-tier.js";
8
8
  export * from "./get-error-message.js";
9
+ export * from "./is-abort-error.js";
9
10
  export * from "./plan.js";
10
11
  export * from "./ports.js";
11
12
  export * from "./product-title.js";
12
13
  export * from "./sentry-distribution.js";
14
+ export * from "./sentry-event-limiter.js";
13
15
  export * from "./sentry-release.js";
14
16
  export * from "./service-logger.js";
15
17
  export * from "./tier.js";
@@ -0,0 +1,2 @@
1
+ export declare function isAbortError(error: unknown): boolean;
2
+ //# sourceMappingURL=is-abort-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-abort-error.d.ts","sourceRoot":"","sources":["../../lib/is-abort-error.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAOpD"}
@@ -0,0 +1,6 @@
1
+ export function isAbortError(error) {
2
+ return (typeof error === "object" &&
3
+ error !== null &&
4
+ "name" in error &&
5
+ (error.name === "AbortError" || error.name === "ResponseAborted"));
6
+ }
@@ -0,0 +1,19 @@
1
+ type LimitedEvent = {
2
+ fingerprint?: string[] | undefined;
3
+ message?: string | undefined;
4
+ exception?: {
5
+ values?: {
6
+ type?: string | undefined;
7
+ value?: string | undefined;
8
+ }[] | undefined;
9
+ } | undefined;
10
+ };
11
+ type SentryEventLimiterOptions = {
12
+ maxPerWindow?: number;
13
+ windowMs?: number;
14
+ maxKeys?: number;
15
+ now?: () => number;
16
+ };
17
+ export declare function createSentryEventLimiter({ maxPerWindow, windowMs, maxKeys, now, }?: SentryEventLimiterOptions): (event: LimitedEvent) => boolean;
18
+ export {};
19
+ //# sourceMappingURL=sentry-event-limiter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sentry-event-limiter.d.ts","sourceRoot":"","sources":["../../lib/sentry-event-limiter.ts"],"names":[],"mappings":"AAAA,KAAK,YAAY,GAAG;IACnB,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACnC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,SAAS,CAAC,EACP;QACA,MAAM,CAAC,EACJ;YAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;SAAE,EAAE,GAC3D,SAAS,CAAC;KACZ,GACD,SAAS,CAAC;CACb,CAAC;AAEF,KAAK,yBAAyB,GAAG;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACnB,CAAC;AAWF,wBAAgB,wBAAwB,CAAC,EACxC,YAAiB,EACjB,QAAyB,EACzB,OAAa,EACb,GAAc,GACd,GAAE,yBAA8B,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAcnE"}
@@ -0,0 +1,25 @@
1
+ function eventKey(event) {
2
+ if (event.fingerprint?.length)
3
+ return event.fingerprint.join("|");
4
+ const exception = event.exception?.values?.at(-1);
5
+ const text = exception
6
+ ? `${exception.type ?? ""}:${exception.value ?? ""}`
7
+ : (event.message ?? "");
8
+ return text.replace(/\d+/g, "N").slice(0, 300);
9
+ }
10
+ export function createSentryEventLimiter({ maxPerWindow = 10, windowMs = 60 * 60 * 1000, maxKeys = 500, now = Date.now, } = {}) {
11
+ const windows = new Map();
12
+ return (event) => {
13
+ const key = eventKey(event);
14
+ const time = now();
15
+ const current = windows.get(key);
16
+ if (!current || time - current.start >= windowMs) {
17
+ if (!current && windows.size >= maxKeys)
18
+ windows.clear();
19
+ windows.set(key, { start: time, count: 1 });
20
+ return true;
21
+ }
22
+ current.count++;
23
+ return current.count <= maxPerWindow;
24
+ };
25
+ }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # @pdfvector/util
2
2
 
3
+ ## 0.6.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#525](https://github.com/phuctm97/pdfvector/pull/525) [`cce2fc7`](https://github.com/phuctm97/pdfvector/commit/cce2fc71b04f02ad0fc5efb52124b1de3cec9342) Thanks [@khanhduyvt0101](https://github.com/khanhduyvt0101)! - Stop swallowing errors and filter Sentry noise explicitly:
8
+
9
+ - Gateway: report unexpected oRPC procedure errors (with RPC path and organization) and Better Auth internal errors, which were turned into 500 responses without reaching Sentry. Report managed instance reconcile jobs that keep failing (3+ attempts) or fail for good, image upgrade failures, Stripe errors hidden behind the add-on purchase recovery state, and admin user Stripe lookups. A failed Stripe webhook now answers 500 instead of 400.
10
+ - Gateway noise policy: request cancellations and our own 4xx answers (validation, bad keys, payment required, rate limits, conflicts) are never reported; third-party 4xx errors (Stripe, Fly) still are.
11
+ - App: report failed queries and mutations and MCP connection failures that only showed a toast or a "failed" state, unless they are cancellations, the user's network, or HTTP errors (the gateway reports those). Chunk-load errors after a deploy now show a reload prompt instead of "Something Went Wrong". Ignore ResizeObserver loop notices and extension URLs.
12
+ - Website: report free-tool connection failures and Make template fetch failures; the Worker drops disconnects, 4xx route answers and CSRF rejections and now tags events with the dist.
13
+ - Every Sentry client rate limits repeated events (10 per hour per error) so a loop can't flood Sentry.
14
+
15
+ ## 0.6.0
16
+
17
+ ### Minor Changes
18
+
19
+ - [#521](https://github.com/phuctm97/pdfvector/pull/521) [`43f714f`](https://github.com/phuctm97/pdfvector/commit/43f714f0a28af7f3d213bfd1042dd2013cb39459) Thanks [@khanhduyvt0101](https://github.com/khanhduyvt0101)! - Add admin provider health: failure and hidden-fallback rates per provider/service over 1 h, 24 h and 7 d, a Provider health card on the admin usage page and a "Needs attention" item on the admin overview.
20
+
21
+ ### Patch Changes
22
+
23
+ - [#521](https://github.com/phuctm97/pdfvector/pull/521) [`43f714f`](https://github.com/phuctm97/pdfvector/commit/43f714f0a28af7f3d213bfd1042dd2013cb39459) Thanks [@khanhduyvt0101](https://github.com/khanhduyvt0101)! - Stop hiding provider failures behind fallbacks:
24
+
25
+ - Semantic Scholar: pace requests per process, retry 429s after `Retry-After` with bounded backoff instead of retrying through the proxy (S2 limits per API key), and record 429/5xx as system errors with the endpoint and response message.
26
+ - Webshare proxy usage now reflects proxy health only; the target's HTTP status is kept in `rawUsage.targetStatus`.
27
+ - Google Document AI: send `imagelessMode` so PDFs of up to 30 pages parse in one call (was 15), and let the max-tier fallback parse larger PDFs in 15-page chunks (up to 200 pages). PDFs over 30 pages skip the failing Document AI call in auto mode.
28
+ - Nano: a PDF without a usable text layer (scanned or image-only) now fails with a clear user-side error that says Nano only reads embedded text, instead of a generic system error.
29
+ - Azure image pre-check failures now record the Azure error code and message.
30
+ - API reference: document the academic search `errors` field (partial results when a provider fails).
31
+
3
32
  ## 0.5.1
4
33
 
5
34
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pdfvector/util",
3
- "version": "0.5.1",
3
+ "version": "0.6.1",
4
4
  "type": "module",
5
5
  "main": "./.tsc/lib/index.js",
6
6
  "exports": {