@beezping/adapter-prisma 0.7.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/LICENSE +21 -0
- package/README.md +48 -0
- package/dist/email.d.cts +19 -0
- package/dist/email.d.ts +19 -0
- package/dist/errors.d.cts +41 -0
- package/dist/errors.d.ts +41 -0
- package/dist/filters.d.cts +74 -0
- package/dist/filters.d.ts +74 -0
- package/dist/i18n.d.cts +67 -0
- package/dist/i18n.d.ts +67 -0
- package/dist/index.cjs +1241 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +363 -0
- package/dist/index.d.ts +363 -0
- package/dist/index.js +1196 -0
- package/dist/index.js.map +1 -0
- package/dist/schema.d.cts +263 -0
- package/dist/schema.d.ts +263 -0
- package/dist/screenshot-storage.d.cts +78 -0
- package/dist/screenshot-storage.d.ts +78 -0
- package/dist/siteping-core.d.cts +17 -0
- package/dist/siteping-core.d.ts +17 -0
- package/dist/store-helpers.d.cts +112 -0
- package/dist/store-helpers.d.ts +112 -0
- package/dist/type-utils.d.cts +58 -0
- package/dist/type-utils.d.ts +58 -0
- package/dist/types.d.cts +947 -0
- package/dist/types.d.ts +947 -0
- package/dist/wire.d.cts +35 -0
- package/dist/wire.d.ts +35 -0
- package/package.json +69 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 NeosiaNexus
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
[](https://www.npmjs.com/package/@beezping/adapter-prisma)
|
|
2
|
+
[](https://siteping.dev/docs/adapters/prisma)
|
|
3
|
+
[](https://www.typescriptlang.org/)
|
|
4
|
+
|
|
5
|
+
# @beezping/adapter-prisma
|
|
6
|
+
|
|
7
|
+
The production server adapter for [SitePing](https://github.com/NeosiaNexus/SitePing) — one endpoint that validates, authenticates, and persists client feedback in your database.
|
|
8
|
+
|
|
9
|
+
**[Documentation](https://siteping.dev/docs/adapters/prisma)** · **[live demo](https://siteping.dev/demo)**
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @beezping/adapter-prisma
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**Peer dependency:** `@prisma/client` ^5 || ^6 || ^7 · Node ≥ 20.
|
|
18
|
+
|
|
19
|
+
## Quick start
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
// app/api/siteping/route.ts — Next.js App Router
|
|
23
|
+
import { createSitepingHandler } from "@beezping/adapter-prisma";
|
|
24
|
+
import { prisma } from "@/lib/prisma";
|
|
25
|
+
|
|
26
|
+
export const { GET, POST, PATCH, DELETE, OPTIONS } = createSitepingHandler({
|
|
27
|
+
prisma,
|
|
28
|
+
apiKey: process.env.SITEPING_API_KEY, // Bearer auth
|
|
29
|
+
allowedOrigins: ["https://my-site.com"], // exact-match CORS
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The handlers are Web-standard `Request` → `Response` — mount them from any framework (Remix, SvelteKit, Hono, …). Generate the required Prisma models with `npx @beezping/cli sync`.
|
|
34
|
+
|
|
35
|
+
## Highlights
|
|
36
|
+
|
|
37
|
+
- **Safe by default** — status changes and deletes require the `apiKey`; in production the factory refuses to start without one. Author emails are redacted for unauthenticated readers and `clientId` never leaves the server
|
|
38
|
+
- **Screenshot storage hook** — upload images to S3/R2/GCS instead of inlining data URLs
|
|
39
|
+
- **Webhooks** — Slack, Discord, or generic POST on each new feedback (5 s timeout, never blocks the submission)
|
|
40
|
+
- **Any store behind the same HTTP surface** — pass `store` instead of `prisma` to mount an in-memory or custom store with identical validation and auth
|
|
41
|
+
|
|
42
|
+
## Documentation
|
|
43
|
+
|
|
44
|
+
All options with their real defaults, the full HTTP reference (bodies, query params, errors, validation limits), the exact Prisma schema, and the security model: **[siteping.dev/docs/adapters/prisma](https://siteping.dev/docs/adapters/prisma)**.
|
|
45
|
+
|
|
46
|
+
## License
|
|
47
|
+
|
|
48
|
+
[MIT](https://github.com/NeosiaNexus/SitePing/blob/main/LICENSE)
|
package/dist/email.d.cts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one email pattern every Siteping surface validates against.
|
|
3
|
+
*
|
|
4
|
+
* The widget's identity modal and the HTTP handler's schema used to disagree
|
|
5
|
+
* (a permissive regex on one side, an ASCII-only default on the other), so an
|
|
6
|
+
* address the modal accepted — and persisted in localStorage for good — came
|
|
7
|
+
* back as a 400 on every submission afterwards. One pattern, imported on both
|
|
8
|
+
* sides, makes that drift impossible.
|
|
9
|
+
*
|
|
10
|
+
* Deliberately Unicode-aware: internationalised local parts and domains
|
|
11
|
+
* (`françois@exemple.fr`, `user@münchen.de`) are real addresses and common in
|
|
12
|
+
* the audience this widget serves. Structure follows the usual rules — a
|
|
13
|
+
* local part of 1 to 64 characters with no leading, trailing or doubled dot,
|
|
14
|
+
* dot-separated domain labels of at most 63 characters that neither start nor
|
|
15
|
+
* end with a hyphen, and a final label of at least two characters.
|
|
16
|
+
*/
|
|
17
|
+
export declare const EMAIL_PATTERN: RegExp;
|
|
18
|
+
/** Whether `value` is an email address Siteping accepts — see {@link EMAIL_PATTERN}. */
|
|
19
|
+
export declare function isValidEmail(value: string): boolean;
|
package/dist/email.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one email pattern every Siteping surface validates against.
|
|
3
|
+
*
|
|
4
|
+
* The widget's identity modal and the HTTP handler's schema used to disagree
|
|
5
|
+
* (a permissive regex on one side, an ASCII-only default on the other), so an
|
|
6
|
+
* address the modal accepted — and persisted in localStorage for good — came
|
|
7
|
+
* back as a 400 on every submission afterwards. One pattern, imported on both
|
|
8
|
+
* sides, makes that drift impossible.
|
|
9
|
+
*
|
|
10
|
+
* Deliberately Unicode-aware: internationalised local parts and domains
|
|
11
|
+
* (`françois@exemple.fr`, `user@münchen.de`) are real addresses and common in
|
|
12
|
+
* the audience this widget serves. Structure follows the usual rules — a
|
|
13
|
+
* local part of 1 to 64 characters with no leading, trailing or doubled dot,
|
|
14
|
+
* dot-separated domain labels of at most 63 characters that neither start nor
|
|
15
|
+
* end with a hyphen, and a final label of at least two characters.
|
|
16
|
+
*/
|
|
17
|
+
export declare const EMAIL_PATTERN: RegExp;
|
|
18
|
+
/** Whether `value` is an email address Siteping accepts — see {@link EMAIL_PATTERN}. */
|
|
19
|
+
export declare function isValidEmail(value: string): boolean;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed error hierarchy for Siteping client/server boundaries.
|
|
3
|
+
*
|
|
4
|
+
* Consumers can `instanceof`-check or read `code` / `retryable` instead of
|
|
5
|
+
* pattern-matching error messages. Designed to be additive on top of the
|
|
6
|
+
* existing store errors (`StoreNotFoundError`, `StoreDuplicateError`) which
|
|
7
|
+
* remain the canonical signals for server-side store implementations.
|
|
8
|
+
*
|
|
9
|
+
* Usage on the widget side (api-client.ts):
|
|
10
|
+
* - fetch failures / aborts / timeouts → `SitepingNetworkError` (retryable)
|
|
11
|
+
* - HTTP 4xx (except 401/403) → `SitepingValidationError` (not retryable)
|
|
12
|
+
* - HTTP 401 / 403 → `SitepingAuthError` (not retryable)
|
|
13
|
+
* - everything else → `SitepingError` generic
|
|
14
|
+
*
|
|
15
|
+
* `retryable` is meta information surfaced to host apps that want to wire
|
|
16
|
+
* their own retry/queue/backoff strategy — the widget already retries
|
|
17
|
+
* network failures via its built-in retry queue.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Discriminant string carried by every `SitepingError`. Subclasses pin a
|
|
21
|
+
* literal value; the base class accepts a wider string so userland can
|
|
22
|
+
* extend the hierarchy without colliding with built-ins.
|
|
23
|
+
*/
|
|
24
|
+
export type SitepingErrorCode = "NETWORK" | "VALIDATION" | "AUTH" | "SERVER" | (string & {});
|
|
25
|
+
export declare class SitepingError<TCode extends SitepingErrorCode = SitepingErrorCode> extends Error {
|
|
26
|
+
readonly code: TCode;
|
|
27
|
+
readonly retryable: boolean;
|
|
28
|
+
constructor(message: string, code: TCode, retryable: boolean);
|
|
29
|
+
}
|
|
30
|
+
/** Network-level failure: connection refused, DNS, CORS, timeout, abort. Retryable. */
|
|
31
|
+
export declare class SitepingNetworkError extends SitepingError<"NETWORK"> {
|
|
32
|
+
constructor(message: string);
|
|
33
|
+
}
|
|
34
|
+
/** Server rejected the request (4xx, not auth). Validation problem on the client side. */
|
|
35
|
+
export declare class SitepingValidationError extends SitepingError<"VALIDATION"> {
|
|
36
|
+
constructor(message: string);
|
|
37
|
+
}
|
|
38
|
+
/** Server rejected auth (401 or 403). Not retryable without fresh credentials. */
|
|
39
|
+
export declare class SitepingAuthError extends SitepingError<"AUTH"> {
|
|
40
|
+
constructor(message: string);
|
|
41
|
+
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed error hierarchy for Siteping client/server boundaries.
|
|
3
|
+
*
|
|
4
|
+
* Consumers can `instanceof`-check or read `code` / `retryable` instead of
|
|
5
|
+
* pattern-matching error messages. Designed to be additive on top of the
|
|
6
|
+
* existing store errors (`StoreNotFoundError`, `StoreDuplicateError`) which
|
|
7
|
+
* remain the canonical signals for server-side store implementations.
|
|
8
|
+
*
|
|
9
|
+
* Usage on the widget side (api-client.ts):
|
|
10
|
+
* - fetch failures / aborts / timeouts → `SitepingNetworkError` (retryable)
|
|
11
|
+
* - HTTP 4xx (except 401/403) → `SitepingValidationError` (not retryable)
|
|
12
|
+
* - HTTP 401 / 403 → `SitepingAuthError` (not retryable)
|
|
13
|
+
* - everything else → `SitepingError` generic
|
|
14
|
+
*
|
|
15
|
+
* `retryable` is meta information surfaced to host apps that want to wire
|
|
16
|
+
* their own retry/queue/backoff strategy — the widget already retries
|
|
17
|
+
* network failures via its built-in retry queue.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Discriminant string carried by every `SitepingError`. Subclasses pin a
|
|
21
|
+
* literal value; the base class accepts a wider string so userland can
|
|
22
|
+
* extend the hierarchy without colliding with built-ins.
|
|
23
|
+
*/
|
|
24
|
+
export type SitepingErrorCode = "NETWORK" | "VALIDATION" | "AUTH" | "SERVER" | (string & {});
|
|
25
|
+
export declare class SitepingError<TCode extends SitepingErrorCode = SitepingErrorCode> extends Error {
|
|
26
|
+
readonly code: TCode;
|
|
27
|
+
readonly retryable: boolean;
|
|
28
|
+
constructor(message: string, code: TCode, retryable: boolean);
|
|
29
|
+
}
|
|
30
|
+
/** Network-level failure: connection refused, DNS, CORS, timeout, abort. Retryable. */
|
|
31
|
+
export declare class SitepingNetworkError extends SitepingError<"NETWORK"> {
|
|
32
|
+
constructor(message: string);
|
|
33
|
+
}
|
|
34
|
+
/** Server rejected the request (4xx, not auth). Validation problem on the client side. */
|
|
35
|
+
export declare class SitepingValidationError extends SitepingError<"VALIDATION"> {
|
|
36
|
+
constructor(message: string);
|
|
37
|
+
}
|
|
38
|
+
/** Server rejected auth (401 or 403). Not retryable without fresh credentials. */
|
|
39
|
+
export declare class SitepingAuthError extends SitepingError<"AUTH"> {
|
|
40
|
+
constructor(message: string);
|
|
41
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared feedback-record filtering and pagination — extracted from
|
|
3
|
+
* `adapter-memory` and `adapter-localstorage` which previously kept two
|
|
4
|
+
* near-identical copies of the same logic. Any adapter that holds an
|
|
5
|
+
* in-memory snapshot of feedbacks can use it.
|
|
6
|
+
*
|
|
7
|
+
* Filtering order matches the historical adapter behaviour:
|
|
8
|
+
* 1. projectName (always required)
|
|
9
|
+
* 2. type
|
|
10
|
+
* 3. status / statuses (`statuses` bucket wins when both are set)
|
|
11
|
+
* 4. url
|
|
12
|
+
* 5. urlPattern
|
|
13
|
+
* 6. search (lowercase substring match on `message`)
|
|
14
|
+
*
|
|
15
|
+
* Pagination goes through `clampPagination`: `limit` capped at 100, `page`
|
|
16
|
+
* 1-based, both clamped up to 1 rather than indexing backwards from the end
|
|
17
|
+
* of the match set. Query adapters reuse the same helper so every store
|
|
18
|
+
* paginates identically.
|
|
19
|
+
*/
|
|
20
|
+
import type { FeedbackQuery, FeedbackRecord } from "./types.cjs";
|
|
21
|
+
/** Default page size when the caller omits `query.limit`. */
|
|
22
|
+
export declare const DEFAULT_PAGE_LIMIT = 50;
|
|
23
|
+
/** Maximum allowed page size — defends against memory blow-ups on hostile callers. */
|
|
24
|
+
export declare const MAX_PAGE_LIMIT = 100;
|
|
25
|
+
export interface FilterResult {
|
|
26
|
+
feedbacks: FeedbackRecord[];
|
|
27
|
+
total: number;
|
|
28
|
+
}
|
|
29
|
+
/** Normalised pagination window — see {@link clampPagination}. */
|
|
30
|
+
export interface Pagination {
|
|
31
|
+
/** 1-based page number, at least 1. */
|
|
32
|
+
page: number;
|
|
33
|
+
/** Page size in `[1, MAX_PAGE_LIMIT]`. */
|
|
34
|
+
limit: number;
|
|
35
|
+
/** Offset of the first row: `(page - 1) * limit`. */
|
|
36
|
+
skip: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Normalise `page` / `limit` to the store contract: `page` is 1-based and
|
|
40
|
+
* clamped up to 1, `limit` defaults to 50 and is clamped into `[1, 100]`,
|
|
41
|
+
* non-finite values fall back to the defaults. `skip` is the derived row
|
|
42
|
+
* offset for query backends (`OFFSET`, Prisma `skip`).
|
|
43
|
+
*
|
|
44
|
+
* Shared by the in-memory pipeline and query adapters (`PrismaStore`) so
|
|
45
|
+
* every store paginates identically — the HTTP schema clamps the same way,
|
|
46
|
+
* but direct callers (dashboard store mode, server actions) reach the store
|
|
47
|
+
* without a schema in front of them.
|
|
48
|
+
*/
|
|
49
|
+
export declare function clampPagination(query: Pick<FeedbackQuery, "page" | "limit">): Pagination;
|
|
50
|
+
/**
|
|
51
|
+
* Whether a {@link clampPagination} offset lies beyond any row a store can
|
|
52
|
+
* hold. `clampPagination` bounds `page` from below only, so a direct caller's
|
|
53
|
+
* huge `page` yields an offset past `Number.MAX_SAFE_INTEGER` — or `Infinity`
|
|
54
|
+
* — that SQL backends reject (`OFFSET` is a 64-bit integer in PostgreSQL and
|
|
55
|
+
* SQLite; Prisma's `skip` rejects non-integers and 64-bit overflow).
|
|
56
|
+
*
|
|
57
|
+
* Every safe integer fits a signed 64-bit offset and no table holds more rows
|
|
58
|
+
* than that, so query adapters answer such a page as empty — with the real
|
|
59
|
+
* `total` — instead of issuing the query: the same result the in-memory
|
|
60
|
+
* pipeline returns.
|
|
61
|
+
*
|
|
62
|
+
* @param skip - The `skip` returned by {@link clampPagination}.
|
|
63
|
+
* @returns `true` when no row can sit at that offset.
|
|
64
|
+
*/
|
|
65
|
+
export declare function isUnreachableOffset(skip: number): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Apply the standard feedback filter + pagination pipeline against an
|
|
68
|
+
* in-memory snapshot. Used by `MemoryStore.getFeedbacks` and
|
|
69
|
+
* `LocalStorageStore.getFeedbacks` so the two never drift.
|
|
70
|
+
*
|
|
71
|
+
* @param items All known feedback records (already include `annotations`).
|
|
72
|
+
* @param query Filter and pagination options. `projectName` is required.
|
|
73
|
+
*/
|
|
74
|
+
export declare function applyFeedbackFilters(items: readonly FeedbackRecord[], query: FeedbackQuery): FilterResult;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared feedback-record filtering and pagination — extracted from
|
|
3
|
+
* `adapter-memory` and `adapter-localstorage` which previously kept two
|
|
4
|
+
* near-identical copies of the same logic. Any adapter that holds an
|
|
5
|
+
* in-memory snapshot of feedbacks can use it.
|
|
6
|
+
*
|
|
7
|
+
* Filtering order matches the historical adapter behaviour:
|
|
8
|
+
* 1. projectName (always required)
|
|
9
|
+
* 2. type
|
|
10
|
+
* 3. status / statuses (`statuses` bucket wins when both are set)
|
|
11
|
+
* 4. url
|
|
12
|
+
* 5. urlPattern
|
|
13
|
+
* 6. search (lowercase substring match on `message`)
|
|
14
|
+
*
|
|
15
|
+
* Pagination goes through `clampPagination`: `limit` capped at 100, `page`
|
|
16
|
+
* 1-based, both clamped up to 1 rather than indexing backwards from the end
|
|
17
|
+
* of the match set. Query adapters reuse the same helper so every store
|
|
18
|
+
* paginates identically.
|
|
19
|
+
*/
|
|
20
|
+
import type { FeedbackQuery, FeedbackRecord } from "./types.js";
|
|
21
|
+
/** Default page size when the caller omits `query.limit`. */
|
|
22
|
+
export declare const DEFAULT_PAGE_LIMIT = 50;
|
|
23
|
+
/** Maximum allowed page size — defends against memory blow-ups on hostile callers. */
|
|
24
|
+
export declare const MAX_PAGE_LIMIT = 100;
|
|
25
|
+
export interface FilterResult {
|
|
26
|
+
feedbacks: FeedbackRecord[];
|
|
27
|
+
total: number;
|
|
28
|
+
}
|
|
29
|
+
/** Normalised pagination window — see {@link clampPagination}. */
|
|
30
|
+
export interface Pagination {
|
|
31
|
+
/** 1-based page number, at least 1. */
|
|
32
|
+
page: number;
|
|
33
|
+
/** Page size in `[1, MAX_PAGE_LIMIT]`. */
|
|
34
|
+
limit: number;
|
|
35
|
+
/** Offset of the first row: `(page - 1) * limit`. */
|
|
36
|
+
skip: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Normalise `page` / `limit` to the store contract: `page` is 1-based and
|
|
40
|
+
* clamped up to 1, `limit` defaults to 50 and is clamped into `[1, 100]`,
|
|
41
|
+
* non-finite values fall back to the defaults. `skip` is the derived row
|
|
42
|
+
* offset for query backends (`OFFSET`, Prisma `skip`).
|
|
43
|
+
*
|
|
44
|
+
* Shared by the in-memory pipeline and query adapters (`PrismaStore`) so
|
|
45
|
+
* every store paginates identically — the HTTP schema clamps the same way,
|
|
46
|
+
* but direct callers (dashboard store mode, server actions) reach the store
|
|
47
|
+
* without a schema in front of them.
|
|
48
|
+
*/
|
|
49
|
+
export declare function clampPagination(query: Pick<FeedbackQuery, "page" | "limit">): Pagination;
|
|
50
|
+
/**
|
|
51
|
+
* Whether a {@link clampPagination} offset lies beyond any row a store can
|
|
52
|
+
* hold. `clampPagination` bounds `page` from below only, so a direct caller's
|
|
53
|
+
* huge `page` yields an offset past `Number.MAX_SAFE_INTEGER` — or `Infinity`
|
|
54
|
+
* — that SQL backends reject (`OFFSET` is a 64-bit integer in PostgreSQL and
|
|
55
|
+
* SQLite; Prisma's `skip` rejects non-integers and 64-bit overflow).
|
|
56
|
+
*
|
|
57
|
+
* Every safe integer fits a signed 64-bit offset and no table holds more rows
|
|
58
|
+
* than that, so query adapters answer such a page as empty — with the real
|
|
59
|
+
* `total` — instead of issuing the query: the same result the in-memory
|
|
60
|
+
* pipeline returns.
|
|
61
|
+
*
|
|
62
|
+
* @param skip - The `skip` returned by {@link clampPagination}.
|
|
63
|
+
* @returns `true` when no row can sit at that offset.
|
|
64
|
+
*/
|
|
65
|
+
export declare function isUnreachableOffset(skip: number): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Apply the standard feedback filter + pagination pipeline against an
|
|
68
|
+
* in-memory snapshot. Used by `MemoryStore.getFeedbacks` and
|
|
69
|
+
* `LocalStorageStore.getFeedbacks` so the two never drift.
|
|
70
|
+
*
|
|
71
|
+
* @param items All known feedback records (already include `annotations`).
|
|
72
|
+
* @param query Filter and pagination options. `projectName` is required.
|
|
73
|
+
*/
|
|
74
|
+
export declare function applyFeedbackFilters(items: readonly FeedbackRecord[], query: FeedbackQuery): FilterResult;
|
package/dist/i18n.d.cts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic i18n machinery shared by the widget and the dashboard.
|
|
3
|
+
*
|
|
4
|
+
* Each package owns its `Translations` interface (their key sets differ) and
|
|
5
|
+
* its locale dictionaries; everything else — locale normalization, the
|
|
6
|
+
* custom-locale registry, lazy loading of built-ins, the translate-function
|
|
7
|
+
* factory, interpolation — is identical and lives here once.
|
|
8
|
+
*
|
|
9
|
+
* The `loaders` map is typed `Record<Exclude<BuiltinLocale, "en">, …>`: the
|
|
10
|
+
* moment a locale code is added to {@link BUILTIN_LOCALES}, every consuming
|
|
11
|
+
* package fails to compile until its loader entry (and therefore its
|
|
12
|
+
* dictionary file) exists. Adding a locale cannot silently fall back to
|
|
13
|
+
* English anymore.
|
|
14
|
+
*/
|
|
15
|
+
import { type BuiltinLocale } from "./types.cjs";
|
|
16
|
+
/**
|
|
17
|
+
* Lazy dictionary loaders for every non-English built-in locale. Use static
|
|
18
|
+
* `() => import("./xx.cjs").then((m) => m.xx)` thunks — bundlers keep
|
|
19
|
+
* emitting one chunk per locale, and only the requested one ships.
|
|
20
|
+
*/
|
|
21
|
+
export type LocaleLoaders<T> = Record<Exclude<BuiltinLocale, "en">, () => Promise<T>>;
|
|
22
|
+
/** Translate function over the message catalog `T`. */
|
|
23
|
+
export type TranslateFunction<T> = (key: keyof T & string) => string;
|
|
24
|
+
/** The i18n API returned by {@link createI18n}. */
|
|
25
|
+
export interface I18n<T> {
|
|
26
|
+
/**
|
|
27
|
+
* Create a translation function for the given locale.
|
|
28
|
+
*
|
|
29
|
+
* Locale resolution: exact language match > English fallback, per key.
|
|
30
|
+
* Non-English built-in locales are lazy-loaded via `loadLocale` — call
|
|
31
|
+
* `await loadLocale(locale)` at init if you want the UI to render in the
|
|
32
|
+
* target language immediately; until the dictionary lands, keys resolve
|
|
33
|
+
* to English.
|
|
34
|
+
*/
|
|
35
|
+
createT(locale: string): TranslateFunction<T>;
|
|
36
|
+
/**
|
|
37
|
+
* Dynamically import a built-in locale and register it. Returns the
|
|
38
|
+
* loaded dictionary, or `null` if the locale isn't a known built-in.
|
|
39
|
+
* Custom locales registered via `registerLocale` bypass this loader —
|
|
40
|
+
* they are already in the registry (and are returned as registered, so a
|
|
41
|
+
* partial custom dictionary comes back partial).
|
|
42
|
+
*/
|
|
43
|
+
loadLocale(locale: string): Promise<Partial<T> | null>;
|
|
44
|
+
/**
|
|
45
|
+
* Register a custom locale at runtime. Partial dictionaries are welcome —
|
|
46
|
+
* missing keys fall back to English per key, so overriding a single
|
|
47
|
+
* string never requires copying the whole catalog.
|
|
48
|
+
*/
|
|
49
|
+
registerLocale(code: string, translations: Partial<T>): void;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Build the i18n machinery for one message catalog.
|
|
53
|
+
*
|
|
54
|
+
* @param en — the complete English catalog, bundled synchronously as the fallback.
|
|
55
|
+
* @param loaders — lazy import thunks for every other built-in locale.
|
|
56
|
+
*/
|
|
57
|
+
export declare function createI18n<T extends Record<keyof T & string, string>>(en: T, loaders: LocaleLoaders<T>): I18n<T>;
|
|
58
|
+
/**
|
|
59
|
+
* Interpolate `{paramName}` placeholders in a translated string with the
|
|
60
|
+
* values from `params`. Stringifies numbers and booleans inline so callers
|
|
61
|
+
* can pass `t("marker.count")` along with `{ count: 3 }` directly.
|
|
62
|
+
*
|
|
63
|
+
* Unknown placeholders are left as-is.
|
|
64
|
+
*/
|
|
65
|
+
export declare function interpolate(template: string, params: Readonly<Record<string, string | number | boolean>>): string;
|
|
66
|
+
/** Shorthand for `interpolate(t(key), params)` — key-checked against the catalog. */
|
|
67
|
+
export declare function tWithParams<K extends string>(t: (key: K) => string, key: K, params: Readonly<Record<string, string | number | boolean>>): string;
|
package/dist/i18n.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic i18n machinery shared by the widget and the dashboard.
|
|
3
|
+
*
|
|
4
|
+
* Each package owns its `Translations` interface (their key sets differ) and
|
|
5
|
+
* its locale dictionaries; everything else — locale normalization, the
|
|
6
|
+
* custom-locale registry, lazy loading of built-ins, the translate-function
|
|
7
|
+
* factory, interpolation — is identical and lives here once.
|
|
8
|
+
*
|
|
9
|
+
* The `loaders` map is typed `Record<Exclude<BuiltinLocale, "en">, …>`: the
|
|
10
|
+
* moment a locale code is added to {@link BUILTIN_LOCALES}, every consuming
|
|
11
|
+
* package fails to compile until its loader entry (and therefore its
|
|
12
|
+
* dictionary file) exists. Adding a locale cannot silently fall back to
|
|
13
|
+
* English anymore.
|
|
14
|
+
*/
|
|
15
|
+
import { type BuiltinLocale } from "./types.js";
|
|
16
|
+
/**
|
|
17
|
+
* Lazy dictionary loaders for every non-English built-in locale. Use static
|
|
18
|
+
* `() => import("./xx.js").then((m) => m.xx)` thunks — bundlers keep
|
|
19
|
+
* emitting one chunk per locale, and only the requested one ships.
|
|
20
|
+
*/
|
|
21
|
+
export type LocaleLoaders<T> = Record<Exclude<BuiltinLocale, "en">, () => Promise<T>>;
|
|
22
|
+
/** Translate function over the message catalog `T`. */
|
|
23
|
+
export type TranslateFunction<T> = (key: keyof T & string) => string;
|
|
24
|
+
/** The i18n API returned by {@link createI18n}. */
|
|
25
|
+
export interface I18n<T> {
|
|
26
|
+
/**
|
|
27
|
+
* Create a translation function for the given locale.
|
|
28
|
+
*
|
|
29
|
+
* Locale resolution: exact language match > English fallback, per key.
|
|
30
|
+
* Non-English built-in locales are lazy-loaded via `loadLocale` — call
|
|
31
|
+
* `await loadLocale(locale)` at init if you want the UI to render in the
|
|
32
|
+
* target language immediately; until the dictionary lands, keys resolve
|
|
33
|
+
* to English.
|
|
34
|
+
*/
|
|
35
|
+
createT(locale: string): TranslateFunction<T>;
|
|
36
|
+
/**
|
|
37
|
+
* Dynamically import a built-in locale and register it. Returns the
|
|
38
|
+
* loaded dictionary, or `null` if the locale isn't a known built-in.
|
|
39
|
+
* Custom locales registered via `registerLocale` bypass this loader —
|
|
40
|
+
* they are already in the registry (and are returned as registered, so a
|
|
41
|
+
* partial custom dictionary comes back partial).
|
|
42
|
+
*/
|
|
43
|
+
loadLocale(locale: string): Promise<Partial<T> | null>;
|
|
44
|
+
/**
|
|
45
|
+
* Register a custom locale at runtime. Partial dictionaries are welcome —
|
|
46
|
+
* missing keys fall back to English per key, so overriding a single
|
|
47
|
+
* string never requires copying the whole catalog.
|
|
48
|
+
*/
|
|
49
|
+
registerLocale(code: string, translations: Partial<T>): void;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Build the i18n machinery for one message catalog.
|
|
53
|
+
*
|
|
54
|
+
* @param en — the complete English catalog, bundled synchronously as the fallback.
|
|
55
|
+
* @param loaders — lazy import thunks for every other built-in locale.
|
|
56
|
+
*/
|
|
57
|
+
export declare function createI18n<T extends Record<keyof T & string, string>>(en: T, loaders: LocaleLoaders<T>): I18n<T>;
|
|
58
|
+
/**
|
|
59
|
+
* Interpolate `{paramName}` placeholders in a translated string with the
|
|
60
|
+
* values from `params`. Stringifies numbers and booleans inline so callers
|
|
61
|
+
* can pass `t("marker.count")` along with `{ count: 3 }` directly.
|
|
62
|
+
*
|
|
63
|
+
* Unknown placeholders are left as-is.
|
|
64
|
+
*/
|
|
65
|
+
export declare function interpolate(template: string, params: Readonly<Record<string, string | number | boolean>>): string;
|
|
66
|
+
/** Shorthand for `interpolate(t(key), params)` — key-checked against the catalog. */
|
|
67
|
+
export declare function tWithParams<K extends string>(t: (key: K) => string, key: K, params: Readonly<Record<string, string | number | boolean>>): string;
|