@beezping/adapter-memory 0.6.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/README.md +37 -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 +274 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +43 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +251 -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 +60 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export { EMAIL_PATTERN, isValidEmail } from "./email.cjs";
|
|
2
|
+
export type { SitepingErrorCode } from "./errors.cjs";
|
|
3
|
+
export { SitepingAuthError, SitepingError, SitepingNetworkError, SitepingValidationError } from "./errors.cjs";
|
|
4
|
+
export type { FilterResult, Pagination } from "./filters.cjs";
|
|
5
|
+
export { applyFeedbackFilters, clampPagination, DEFAULT_PAGE_LIMIT, isUnreachableOffset, MAX_PAGE_LIMIT, } from "./filters.cjs";
|
|
6
|
+
export type { I18n, LocaleLoaders, TranslateFunction } from "./i18n.cjs";
|
|
7
|
+
export { createI18n, interpolate, tWithParams } from "./i18n.cjs";
|
|
8
|
+
export type { FieldDef, IndexDef, ModelDef, PrismaNativeType, PrismaScalarType, RelationDef, RelationKind, RelationOnDelete, SitepingModelFieldName, SitepingModelName, } from "./schema.cjs";
|
|
9
|
+
export { isRelationField, isScalarField, SITEPING_MODELS } from "./schema.cjs";
|
|
10
|
+
export type { ScreenshotStorage } from "./screenshot-storage.cjs";
|
|
11
|
+
export type { CollectionStore, CollectionStoreBackend } from "./store-helpers.cjs";
|
|
12
|
+
export { buildAnnotationRecord, buildFeedbackRecord, createCollectionStore } from "./store-helpers.cjs";
|
|
13
|
+
export type { AssertEqual, IfEquals, Prettify, Serialized } from "./type-utils.cjs";
|
|
14
|
+
export { hasOwn, isRecord } from "./type-utils.cjs";
|
|
15
|
+
export type { AnchorData, AnnotationCreateInput, AnnotationPayload, AnnotationRecord, AnnotationResponse, BuiltinLocale, ClosedFeedbackStatus, ConsoleDiagnosticEntry, ConsoleDiagnosticLevel, DiagnosticsCaptureOptions, DiagnosticsSnapshot, FeedbackCreateInput, FeedbackCreateOutcome, FeedbackPage, FeedbackPayload, FeedbackQuery, FeedbackRecord, FeedbackResponse, FeedbackResponseList, FeedbackStatus, FeedbackType, FeedbackUpdateInput, NetworkDiagnosticEntry, OpenFeedbackStatus, PageScope, RectData, ScreenshotRegion, SitepingBaseConfig, SitepingConfig, SitepingDeepLinkOptions, SitepingHeadersOption, SitepingHttpConfig, SitepingIdentity, SitepingInstance, SitepingLocale, SitepingPosition, SitepingPublicEventListener, SitepingPublicEvents, SitepingRequestCredentials, SitepingSkipReason, SitepingStore, SitepingStoreConfig, SitepingTheme, SitepingUnsubscribe, } from "./types.cjs";
|
|
16
|
+
export { BUILTIN_LOCALES, CLOSED_FEEDBACK_STATUSES, CONSOLE_DIAGNOSTIC_LEVELS, DEFAULT_REQUEST_CREDENTIALS, describeInvalidRequestCredentials, FEEDBACK_STATUSES, FEEDBACK_TYPES, flattenAnnotation, isClosedStatus, isRequestCredentials, isStoreDuplicate, isStoreNotFound, isStorePersistence, OPEN_FEEDBACK_STATUSES, REQUEST_CREDENTIALS_MODES, StoreDuplicateError, StoreNotFoundError, StorePersistenceError, toFeedbackUpdate, } from "./types.cjs";
|
|
17
|
+
export { errorFromResponse, feedbackQueryToSearchParams, networkErrorFromException } from "./wire.cjs";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export { EMAIL_PATTERN, isValidEmail } from "./email.js";
|
|
2
|
+
export type { SitepingErrorCode } from "./errors.js";
|
|
3
|
+
export { SitepingAuthError, SitepingError, SitepingNetworkError, SitepingValidationError } from "./errors.js";
|
|
4
|
+
export type { FilterResult, Pagination } from "./filters.js";
|
|
5
|
+
export { applyFeedbackFilters, clampPagination, DEFAULT_PAGE_LIMIT, isUnreachableOffset, MAX_PAGE_LIMIT, } from "./filters.js";
|
|
6
|
+
export type { I18n, LocaleLoaders, TranslateFunction } from "./i18n.js";
|
|
7
|
+
export { createI18n, interpolate, tWithParams } from "./i18n.js";
|
|
8
|
+
export type { FieldDef, IndexDef, ModelDef, PrismaNativeType, PrismaScalarType, RelationDef, RelationKind, RelationOnDelete, SitepingModelFieldName, SitepingModelName, } from "./schema.js";
|
|
9
|
+
export { isRelationField, isScalarField, SITEPING_MODELS } from "./schema.js";
|
|
10
|
+
export type { ScreenshotStorage } from "./screenshot-storage.js";
|
|
11
|
+
export type { CollectionStore, CollectionStoreBackend } from "./store-helpers.js";
|
|
12
|
+
export { buildAnnotationRecord, buildFeedbackRecord, createCollectionStore } from "./store-helpers.js";
|
|
13
|
+
export type { AssertEqual, IfEquals, Prettify, Serialized } from "./type-utils.js";
|
|
14
|
+
export { hasOwn, isRecord } from "./type-utils.js";
|
|
15
|
+
export type { AnchorData, AnnotationCreateInput, AnnotationPayload, AnnotationRecord, AnnotationResponse, BuiltinLocale, ClosedFeedbackStatus, ConsoleDiagnosticEntry, ConsoleDiagnosticLevel, DiagnosticsCaptureOptions, DiagnosticsSnapshot, FeedbackCreateInput, FeedbackCreateOutcome, FeedbackPage, FeedbackPayload, FeedbackQuery, FeedbackRecord, FeedbackResponse, FeedbackResponseList, FeedbackStatus, FeedbackType, FeedbackUpdateInput, NetworkDiagnosticEntry, OpenFeedbackStatus, PageScope, RectData, ScreenshotRegion, SitepingBaseConfig, SitepingConfig, SitepingDeepLinkOptions, SitepingHeadersOption, SitepingHttpConfig, SitepingIdentity, SitepingInstance, SitepingLocale, SitepingPosition, SitepingPublicEventListener, SitepingPublicEvents, SitepingRequestCredentials, SitepingSkipReason, SitepingStore, SitepingStoreConfig, SitepingTheme, SitepingUnsubscribe, } from "./types.js";
|
|
16
|
+
export { BUILTIN_LOCALES, CLOSED_FEEDBACK_STATUSES, CONSOLE_DIAGNOSTIC_LEVELS, DEFAULT_REQUEST_CREDENTIALS, describeInvalidRequestCredentials, FEEDBACK_STATUSES, FEEDBACK_TYPES, flattenAnnotation, isClosedStatus, isRequestCredentials, isStoreDuplicate, isStoreNotFound, isStorePersistence, OPEN_FEEDBACK_STATUSES, REQUEST_CREDENTIALS_MODES, StoreDuplicateError, StoreNotFoundError, StorePersistenceError, toFeedbackUpdate, } from "./types.js";
|
|
17
|
+
export { errorFromResponse, feedbackQueryToSearchParams, networkErrorFromException } from "./wire.js";
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Record-construction helpers and the collection-store engine.
|
|
3
|
+
*
|
|
4
|
+
* Every snapshot-style adapter (memory, localStorage, flat file, KV, …)
|
|
5
|
+
* needs the same three ingredients: turn a `FeedbackCreateInput` into a
|
|
6
|
+
* `FeedbackRecord` (null-normalizing optional fields, stamping ids and
|
|
7
|
+
* timestamps), filter/paginate with `applyFeedbackFilters`, and implement
|
|
8
|
+
* the dedup/update/delete choreography of the `SitepingStore` contract.
|
|
9
|
+
*
|
|
10
|
+
* `buildFeedbackRecord` / `buildAnnotationRecord` cover the first part for
|
|
11
|
+
* any adapter. `createCollectionStore` covers all of it: give it `load`,
|
|
12
|
+
* `persist`, and `generateId`, and it returns a fully conformant
|
|
13
|
+
* `SitepingStore` — writing a new snapshot adapter is ~20 lines plus its
|
|
14
|
+
* storage specifics.
|
|
15
|
+
*/
|
|
16
|
+
import type { AnnotationCreateInput, AnnotationRecord, FeedbackCreateInput, FeedbackRecord, SitepingStore } from "./types.cjs";
|
|
17
|
+
/**
|
|
18
|
+
* Build a persisted `AnnotationRecord` from its create input — normalizes
|
|
19
|
+
* the optional anchor fields to `null` and stamps identity/timestamp.
|
|
20
|
+
*/
|
|
21
|
+
export declare function buildAnnotationRecord(input: AnnotationCreateInput, ctx: {
|
|
22
|
+
id: string;
|
|
23
|
+
feedbackId: string;
|
|
24
|
+
now: Date;
|
|
25
|
+
}): AnnotationRecord;
|
|
26
|
+
/**
|
|
27
|
+
* Build a persisted `FeedbackRecord` (with its annotations) from a create
|
|
28
|
+
* input — normalizes every optional field to `null` and stamps ids and
|
|
29
|
+
* timestamps. Adapters without external screenshot storage keep the data
|
|
30
|
+
* URL inline on `screenshotUrl`, which is what this helper does; adapters
|
|
31
|
+
* with a `ScreenshotStorage` upload first and override `screenshotUrl`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function buildFeedbackRecord(input: FeedbackCreateInput, ctx: {
|
|
34
|
+
id: string;
|
|
35
|
+
annotationId: () => string;
|
|
36
|
+
now?: Date;
|
|
37
|
+
}): FeedbackRecord;
|
|
38
|
+
/**
|
|
39
|
+
* Storage primitives behind a collection store. `load`/`persist` may be
|
|
40
|
+
* sync or async — the engine awaits both, so in-memory arrays, localStorage
|
|
41
|
+
* and async KV stores all fit the same three functions.
|
|
42
|
+
*/
|
|
43
|
+
export interface CollectionStoreBackend {
|
|
44
|
+
/**
|
|
45
|
+
* Return the current full snapshot of feedback records. The engine never
|
|
46
|
+
* mutates this array — handing out a live cache is safe.
|
|
47
|
+
*/
|
|
48
|
+
load(): FeedbackRecord[] | Promise<FeedbackRecord[]>;
|
|
49
|
+
/**
|
|
50
|
+
* Persist the full snapshot — always a new array, never the one `load()`
|
|
51
|
+
* returned. Throw `StorePersistenceError` when the write is lost (quota,
|
|
52
|
+
* storage disabled, …) — never swallow the failure. Because the loaded
|
|
53
|
+
* snapshot is left untouched, a throw here leaves a cached `load()` result
|
|
54
|
+
* consistent with durable storage: no phantom record, no half-applied
|
|
55
|
+
* update.
|
|
56
|
+
*/
|
|
57
|
+
persist(feedbacks: FeedbackRecord[]): void | Promise<void>;
|
|
58
|
+
/** Generate a unique id for a new feedback or annotation record. */
|
|
59
|
+
generateId(): string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* A `SitepingStore` with the optional `verifyProjectOwnership` and
|
|
63
|
+
* `createFeedbackIfAbsent` guaranteed — what `createCollectionStore` returns.
|
|
64
|
+
*/
|
|
65
|
+
export type CollectionStore = SitepingStore & Required<Pick<SitepingStore, "verifyProjectOwnership" | "createFeedbackIfAbsent">>;
|
|
66
|
+
/**
|
|
67
|
+
* Build a fully conformant `SitepingStore` on top of a snapshot backend.
|
|
68
|
+
*
|
|
69
|
+
* The engine implements the whole store contract: clientId dedup (idempotent
|
|
70
|
+
* create, with `createFeedbackIfAbsent` reporting inserts), newest-first
|
|
71
|
+
* ordering, the standard filter/pagination pipeline,
|
|
72
|
+
* `StoreNotFoundError` on missing update/delete, project-scoped bulk delete,
|
|
73
|
+
* and `verifyProjectOwnership`. The snapshot returned by `load` is never
|
|
74
|
+
* mutated: every write hands `persist` a new array, so a failed write leaves
|
|
75
|
+
* a cached snapshot exactly as it was. When `persist` fails during `createFeedback`
|
|
76
|
+
* and the record carries an inline screenshot, the engine retries once
|
|
77
|
+
* without the screenshot (by far the heaviest field) so the text feedback
|
|
78
|
+
* survives a storage-quota hit; if that also fails, the error propagates —
|
|
79
|
+
* returning the record would claim a success that was never persisted.
|
|
80
|
+
*
|
|
81
|
+
* Every read-modify-write mutation (`createFeedbackIfAbsent`,
|
|
82
|
+
* `createFeedback`, `updateFeedback`, `deleteFeedback`,
|
|
83
|
+
* `deleteAllFeedbacks`) runs through one promise queue per returned store,
|
|
84
|
+
* so its `load` → check → `persist` sequence never interleaves with another
|
|
85
|
+
* mutation of the same instance. That makes `createFeedbackIfAbsent` report
|
|
86
|
+
* `created: true` exactly once per `clientId` and prevents concurrent writes
|
|
87
|
+
* from overwriting each other's snapshot. The guarantee is scoped to one
|
|
88
|
+
* store instance in one JS process: two instances over the same storage (two
|
|
89
|
+
* server processes on a shared file, two browser tabs on the same
|
|
90
|
+
* localStorage key) are not coordinated — backends that need that must
|
|
91
|
+
* provide their own atomic primitive (a unique constraint, a transaction, a
|
|
92
|
+
* compare-and-set). A failed mutation rejects with its original error and
|
|
93
|
+
* does not block the ones queued after it. Reads are not queued: they see the
|
|
94
|
+
* last persisted snapshot.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* export class MemoryStore implements SitepingStore {
|
|
99
|
+
* private feedbacks: FeedbackRecord[] = [];
|
|
100
|
+
* private readonly store = createCollectionStore({
|
|
101
|
+
* load: () => this.feedbacks,
|
|
102
|
+
* persist: (next) => {
|
|
103
|
+
* this.feedbacks = next;
|
|
104
|
+
* },
|
|
105
|
+
* generateId: () => crypto.randomUUID(),
|
|
106
|
+
* });
|
|
107
|
+
* createFeedback = this.store.createFeedback;
|
|
108
|
+
* // …delegate the remaining methods the same way
|
|
109
|
+
* }
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
export declare function createCollectionStore(backend: CollectionStoreBackend): CollectionStore;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Record-construction helpers and the collection-store engine.
|
|
3
|
+
*
|
|
4
|
+
* Every snapshot-style adapter (memory, localStorage, flat file, KV, …)
|
|
5
|
+
* needs the same three ingredients: turn a `FeedbackCreateInput` into a
|
|
6
|
+
* `FeedbackRecord` (null-normalizing optional fields, stamping ids and
|
|
7
|
+
* timestamps), filter/paginate with `applyFeedbackFilters`, and implement
|
|
8
|
+
* the dedup/update/delete choreography of the `SitepingStore` contract.
|
|
9
|
+
*
|
|
10
|
+
* `buildFeedbackRecord` / `buildAnnotationRecord` cover the first part for
|
|
11
|
+
* any adapter. `createCollectionStore` covers all of it: give it `load`,
|
|
12
|
+
* `persist`, and `generateId`, and it returns a fully conformant
|
|
13
|
+
* `SitepingStore` — writing a new snapshot adapter is ~20 lines plus its
|
|
14
|
+
* storage specifics.
|
|
15
|
+
*/
|
|
16
|
+
import type { AnnotationCreateInput, AnnotationRecord, FeedbackCreateInput, FeedbackRecord, SitepingStore } from "./types.js";
|
|
17
|
+
/**
|
|
18
|
+
* Build a persisted `AnnotationRecord` from its create input — normalizes
|
|
19
|
+
* the optional anchor fields to `null` and stamps identity/timestamp.
|
|
20
|
+
*/
|
|
21
|
+
export declare function buildAnnotationRecord(input: AnnotationCreateInput, ctx: {
|
|
22
|
+
id: string;
|
|
23
|
+
feedbackId: string;
|
|
24
|
+
now: Date;
|
|
25
|
+
}): AnnotationRecord;
|
|
26
|
+
/**
|
|
27
|
+
* Build a persisted `FeedbackRecord` (with its annotations) from a create
|
|
28
|
+
* input — normalizes every optional field to `null` and stamps ids and
|
|
29
|
+
* timestamps. Adapters without external screenshot storage keep the data
|
|
30
|
+
* URL inline on `screenshotUrl`, which is what this helper does; adapters
|
|
31
|
+
* with a `ScreenshotStorage` upload first and override `screenshotUrl`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function buildFeedbackRecord(input: FeedbackCreateInput, ctx: {
|
|
34
|
+
id: string;
|
|
35
|
+
annotationId: () => string;
|
|
36
|
+
now?: Date;
|
|
37
|
+
}): FeedbackRecord;
|
|
38
|
+
/**
|
|
39
|
+
* Storage primitives behind a collection store. `load`/`persist` may be
|
|
40
|
+
* sync or async — the engine awaits both, so in-memory arrays, localStorage
|
|
41
|
+
* and async KV stores all fit the same three functions.
|
|
42
|
+
*/
|
|
43
|
+
export interface CollectionStoreBackend {
|
|
44
|
+
/**
|
|
45
|
+
* Return the current full snapshot of feedback records. The engine never
|
|
46
|
+
* mutates this array — handing out a live cache is safe.
|
|
47
|
+
*/
|
|
48
|
+
load(): FeedbackRecord[] | Promise<FeedbackRecord[]>;
|
|
49
|
+
/**
|
|
50
|
+
* Persist the full snapshot — always a new array, never the one `load()`
|
|
51
|
+
* returned. Throw `StorePersistenceError` when the write is lost (quota,
|
|
52
|
+
* storage disabled, …) — never swallow the failure. Because the loaded
|
|
53
|
+
* snapshot is left untouched, a throw here leaves a cached `load()` result
|
|
54
|
+
* consistent with durable storage: no phantom record, no half-applied
|
|
55
|
+
* update.
|
|
56
|
+
*/
|
|
57
|
+
persist(feedbacks: FeedbackRecord[]): void | Promise<void>;
|
|
58
|
+
/** Generate a unique id for a new feedback or annotation record. */
|
|
59
|
+
generateId(): string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* A `SitepingStore` with the optional `verifyProjectOwnership` and
|
|
63
|
+
* `createFeedbackIfAbsent` guaranteed — what `createCollectionStore` returns.
|
|
64
|
+
*/
|
|
65
|
+
export type CollectionStore = SitepingStore & Required<Pick<SitepingStore, "verifyProjectOwnership" | "createFeedbackIfAbsent">>;
|
|
66
|
+
/**
|
|
67
|
+
* Build a fully conformant `SitepingStore` on top of a snapshot backend.
|
|
68
|
+
*
|
|
69
|
+
* The engine implements the whole store contract: clientId dedup (idempotent
|
|
70
|
+
* create, with `createFeedbackIfAbsent` reporting inserts), newest-first
|
|
71
|
+
* ordering, the standard filter/pagination pipeline,
|
|
72
|
+
* `StoreNotFoundError` on missing update/delete, project-scoped bulk delete,
|
|
73
|
+
* and `verifyProjectOwnership`. The snapshot returned by `load` is never
|
|
74
|
+
* mutated: every write hands `persist` a new array, so a failed write leaves
|
|
75
|
+
* a cached snapshot exactly as it was. When `persist` fails during `createFeedback`
|
|
76
|
+
* and the record carries an inline screenshot, the engine retries once
|
|
77
|
+
* without the screenshot (by far the heaviest field) so the text feedback
|
|
78
|
+
* survives a storage-quota hit; if that also fails, the error propagates —
|
|
79
|
+
* returning the record would claim a success that was never persisted.
|
|
80
|
+
*
|
|
81
|
+
* Every read-modify-write mutation (`createFeedbackIfAbsent`,
|
|
82
|
+
* `createFeedback`, `updateFeedback`, `deleteFeedback`,
|
|
83
|
+
* `deleteAllFeedbacks`) runs through one promise queue per returned store,
|
|
84
|
+
* so its `load` → check → `persist` sequence never interleaves with another
|
|
85
|
+
* mutation of the same instance. That makes `createFeedbackIfAbsent` report
|
|
86
|
+
* `created: true` exactly once per `clientId` and prevents concurrent writes
|
|
87
|
+
* from overwriting each other's snapshot. The guarantee is scoped to one
|
|
88
|
+
* store instance in one JS process: two instances over the same storage (two
|
|
89
|
+
* server processes on a shared file, two browser tabs on the same
|
|
90
|
+
* localStorage key) are not coordinated — backends that need that must
|
|
91
|
+
* provide their own atomic primitive (a unique constraint, a transaction, a
|
|
92
|
+
* compare-and-set). A failed mutation rejects with its original error and
|
|
93
|
+
* does not block the ones queued after it. Reads are not queued: they see the
|
|
94
|
+
* last persisted snapshot.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* export class MemoryStore implements SitepingStore {
|
|
99
|
+
* private feedbacks: FeedbackRecord[] = [];
|
|
100
|
+
* private readonly store = createCollectionStore({
|
|
101
|
+
* load: () => this.feedbacks,
|
|
102
|
+
* persist: (next) => {
|
|
103
|
+
* this.feedbacks = next;
|
|
104
|
+
* },
|
|
105
|
+
* generateId: () => crypto.randomUUID(),
|
|
106
|
+
* });
|
|
107
|
+
* createFeedback = this.store.createFeedback;
|
|
108
|
+
* // …delegate the remaining methods the same way
|
|
109
|
+
* }
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
export declare function createCollectionStore(backend: CollectionStoreBackend): CollectionStore;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* General-purpose TypeScript utility types used across `@beezping/*`.
|
|
3
|
+
*
|
|
4
|
+
* These are kept dependency-free and re-exported from the package entry
|
|
5
|
+
* so adapters and integrators can rely on the same primitives the core
|
|
6
|
+
* uses internally.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Force TypeScript to expand a computed type into a flat object literal in
|
|
10
|
+
* tooltips and error messages. Purely cosmetic — same structural type, just
|
|
11
|
+
* easier to read.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* type Raw = Omit<FeedbackRecord, "annotations"> & { annotations: number };
|
|
15
|
+
* type Pretty = Prettify<Raw>; // displayed as a flat object
|
|
16
|
+
*/
|
|
17
|
+
export type Prettify<T> = {
|
|
18
|
+
[K in keyof T]: T[K];
|
|
19
|
+
} & {};
|
|
20
|
+
/**
|
|
21
|
+
* Returns `Y` when `A` is exactly assignable to `B` and vice-versa,
|
|
22
|
+
* otherwise `N`. Powers compile-time equality assertions.
|
|
23
|
+
*/
|
|
24
|
+
export type IfEquals<A, B, Y = true, N = false> = (<T>() => T extends A ? 1 : 2) extends <T>() => T extends B ? 1 : 2 ? Y : N;
|
|
25
|
+
/**
|
|
26
|
+
* Compile-time exact-type guard — resolves to `true` when `Actual` and
|
|
27
|
+
* `Expected` are identical, `never` otherwise. Assign the result to a
|
|
28
|
+
* `const _lock: AssertEqual<A, B> = true;` so any drift becomes a compile
|
|
29
|
+
* error at the declaration site.
|
|
30
|
+
*/
|
|
31
|
+
export type AssertEqual<Actual, Expected> = IfEquals<Actual, Expected, true, never>;
|
|
32
|
+
/**
|
|
33
|
+
* JSON-serialized shape of `T` — the wire form produced by `Response.json()`
|
|
34
|
+
* / `JSON.stringify`: `Date` becomes ISO `string` (nullability preserved),
|
|
35
|
+
* arrays are serialized element-wise, everything else is untouched.
|
|
36
|
+
*
|
|
37
|
+
* Used to derive the `*Response` API types from the `*Record` store types so
|
|
38
|
+
* the two can never drift: add a field to `FeedbackRecord` and
|
|
39
|
+
* `FeedbackResponse` follows automatically.
|
|
40
|
+
*/
|
|
41
|
+
export type Serialized<T> = {
|
|
42
|
+
[K in keyof T]: T[K] extends Date ? string : T[K] extends Date | null ? string | null : T[K] extends (infer U)[] ? Serialized<U>[] : T[K];
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Type guard that narrows `value` to a non-null `Record<PropertyKey, unknown>`.
|
|
46
|
+
* Useful when validating arbitrary inputs before reading fields.
|
|
47
|
+
*/
|
|
48
|
+
export declare function isRecord(value: unknown): value is Record<PropertyKey, unknown>;
|
|
49
|
+
/**
|
|
50
|
+
* Returns true when `value` is an object that exposes the requested key.
|
|
51
|
+
* Type-narrows `value` so the property can be accessed without further
|
|
52
|
+
* casting — a strictly typed replacement for `"k" in obj`.
|
|
53
|
+
*
|
|
54
|
+
* Named after the standardised `Object.hasOwn` helper rather than the
|
|
55
|
+
* legacy `Object.prototype.hasOwnProperty`, which the linter forbids
|
|
56
|
+
* shadowing.
|
|
57
|
+
*/
|
|
58
|
+
export declare function hasOwn<K extends PropertyKey>(value: unknown, key: K): value is Record<K, unknown>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* General-purpose TypeScript utility types used across `@beezping/*`.
|
|
3
|
+
*
|
|
4
|
+
* These are kept dependency-free and re-exported from the package entry
|
|
5
|
+
* so adapters and integrators can rely on the same primitives the core
|
|
6
|
+
* uses internally.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Force TypeScript to expand a computed type into a flat object literal in
|
|
10
|
+
* tooltips and error messages. Purely cosmetic — same structural type, just
|
|
11
|
+
* easier to read.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* type Raw = Omit<FeedbackRecord, "annotations"> & { annotations: number };
|
|
15
|
+
* type Pretty = Prettify<Raw>; // displayed as a flat object
|
|
16
|
+
*/
|
|
17
|
+
export type Prettify<T> = {
|
|
18
|
+
[K in keyof T]: T[K];
|
|
19
|
+
} & {};
|
|
20
|
+
/**
|
|
21
|
+
* Returns `Y` when `A` is exactly assignable to `B` and vice-versa,
|
|
22
|
+
* otherwise `N`. Powers compile-time equality assertions.
|
|
23
|
+
*/
|
|
24
|
+
export type IfEquals<A, B, Y = true, N = false> = (<T>() => T extends A ? 1 : 2) extends <T>() => T extends B ? 1 : 2 ? Y : N;
|
|
25
|
+
/**
|
|
26
|
+
* Compile-time exact-type guard — resolves to `true` when `Actual` and
|
|
27
|
+
* `Expected` are identical, `never` otherwise. Assign the result to a
|
|
28
|
+
* `const _lock: AssertEqual<A, B> = true;` so any drift becomes a compile
|
|
29
|
+
* error at the declaration site.
|
|
30
|
+
*/
|
|
31
|
+
export type AssertEqual<Actual, Expected> = IfEquals<Actual, Expected, true, never>;
|
|
32
|
+
/**
|
|
33
|
+
* JSON-serialized shape of `T` — the wire form produced by `Response.json()`
|
|
34
|
+
* / `JSON.stringify`: `Date` becomes ISO `string` (nullability preserved),
|
|
35
|
+
* arrays are serialized element-wise, everything else is untouched.
|
|
36
|
+
*
|
|
37
|
+
* Used to derive the `*Response` API types from the `*Record` store types so
|
|
38
|
+
* the two can never drift: add a field to `FeedbackRecord` and
|
|
39
|
+
* `FeedbackResponse` follows automatically.
|
|
40
|
+
*/
|
|
41
|
+
export type Serialized<T> = {
|
|
42
|
+
[K in keyof T]: T[K] extends Date ? string : T[K] extends Date | null ? string | null : T[K] extends (infer U)[] ? Serialized<U>[] : T[K];
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Type guard that narrows `value` to a non-null `Record<PropertyKey, unknown>`.
|
|
46
|
+
* Useful when validating arbitrary inputs before reading fields.
|
|
47
|
+
*/
|
|
48
|
+
export declare function isRecord(value: unknown): value is Record<PropertyKey, unknown>;
|
|
49
|
+
/**
|
|
50
|
+
* Returns true when `value` is an object that exposes the requested key.
|
|
51
|
+
* Type-narrows `value` so the property can be accessed without further
|
|
52
|
+
* casting — a strictly typed replacement for `"k" in obj`.
|
|
53
|
+
*
|
|
54
|
+
* Named after the standardised `Object.hasOwn` helper rather than the
|
|
55
|
+
* legacy `Object.prototype.hasOwnProperty`, which the linter forbids
|
|
56
|
+
* shadowing.
|
|
57
|
+
*/
|
|
58
|
+
export declare function hasOwn<K extends PropertyKey>(value: unknown, key: K): value is Record<K, unknown>;
|