@beezping/adapter-memory 0.6.0 → 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 +10 -8
- package/dist/beezping-core.d.cts +20 -0
- package/dist/beezping-core.d.ts +20 -0
- package/dist/concurrency.d.cts +14 -0
- package/dist/concurrency.d.ts +14 -0
- package/dist/constants/schema.d.cts +239 -0
- package/dist/constants/schema.d.ts +239 -0
- package/dist/deep-link.d.cts +14 -0
- package/dist/deep-link.d.ts +14 -0
- package/dist/email.d.cts +8 -5
- package/dist/email.d.ts +8 -5
- package/dist/errors.d.cts +28 -14
- package/dist/errors.d.ts +28 -14
- package/dist/filters.d.cts +15 -7
- package/dist/filters.d.ts +15 -7
- package/dist/i18n.d.cts +18 -0
- package/dist/i18n.d.ts +18 -0
- package/dist/index.cjs +99 -61
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -7
- package/dist/index.d.ts +9 -7
- package/dist/index.js +99 -61
- package/dist/index.js.map +1 -1
- package/dist/schema.d.cts +12 -195
- package/dist/schema.d.ts +12 -195
- package/dist/screenshot-storage.d.cts +55 -30
- package/dist/screenshot-storage.d.ts +55 -30
- package/dist/store-helpers.d.cts +62 -34
- package/dist/store-helpers.d.ts +62 -34
- package/dist/type-utils.d.cts +8 -0
- package/dist/type-utils.d.ts +8 -0
- package/dist/types.d.cts +413 -154
- package/dist/types.d.ts +413 -154
- package/dist/wire.d.cts +42 -9
- package/dist/wire.d.ts +42 -9
- package/package.json +7 -8
- package/dist/siteping-core.d.cts +0 -17
- package/dist/siteping-core.d.ts +0 -17
package/dist/schema.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Beezping database models — single source of truth.
|
|
3
3
|
*
|
|
4
4
|
* Used by:
|
|
5
5
|
* - CLI to generate Prisma schema (via prisma-ast)
|
|
@@ -9,11 +9,12 @@
|
|
|
9
9
|
* This is a TS representation, NOT a .prisma file.
|
|
10
10
|
* The CLI generates the actual Prisma schema from this definition.
|
|
11
11
|
*/
|
|
12
|
-
|
|
12
|
+
import type { BEEZPING_MODELS } from "./constants/schema.cjs";
|
|
13
|
+
/** Prisma scalar types supported by Beezping field definitions. */
|
|
13
14
|
export type PrismaScalarType = "String" | "Boolean" | "Int" | "BigInt" | "Float" | "Decimal" | "DateTime" | "Json" | "Bytes";
|
|
14
15
|
/** Prisma native column hints applied via `@db.<NativeType>`. */
|
|
15
16
|
export type PrismaNativeType = "Text" | "VarChar" | "Char" | "MediumText" | "LongText" | (string & {});
|
|
16
|
-
/** Relation cardinality between two
|
|
17
|
+
/** Relation cardinality between two Beezping models. */
|
|
17
18
|
export type RelationKind = "1-to-many" | "many-to-1";
|
|
18
19
|
/** Prisma `onDelete` referential action. */
|
|
19
20
|
export type RelationOnDelete = "Cascade" | "Restrict" | "NoAction" | "SetNull" | "SetDefault";
|
|
@@ -33,7 +34,7 @@ export interface RelationDef {
|
|
|
33
34
|
onDelete?: RelationOnDelete;
|
|
34
35
|
}
|
|
35
36
|
/**
|
|
36
|
-
* Definition of a single field in a
|
|
37
|
+
* Definition of a single field in a Beezping database model.
|
|
37
38
|
*
|
|
38
39
|
* The interface intentionally keeps a wide structural shape so it stays
|
|
39
40
|
* easy to extend, but consumers can narrow via {@link isRelationField} /
|
|
@@ -63,201 +64,17 @@ export declare function isRelationField(field: FieldDef): field is FieldDef & {
|
|
|
63
64
|
export declare function isScalarField(field: FieldDef): field is FieldDef & {
|
|
64
65
|
relation?: undefined;
|
|
65
66
|
};
|
|
66
|
-
/** Definition of a composite index on a
|
|
67
|
+
/** Definition of a composite index on a Beezping database model. */
|
|
67
68
|
export interface IndexDef {
|
|
68
69
|
fields: readonly string[];
|
|
69
70
|
}
|
|
70
|
-
/** Definition of a single
|
|
71
|
+
/** Definition of a single Beezping database model (fields + indexes). */
|
|
71
72
|
export interface ModelDef {
|
|
72
73
|
fields: Record<string, FieldDef>;
|
|
73
74
|
indexes?: readonly IndexDef[];
|
|
74
75
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
readonly isId: true;
|
|
81
|
-
readonly default: "cuid()";
|
|
82
|
-
};
|
|
83
|
-
readonly projectName: {
|
|
84
|
-
readonly type: "String";
|
|
85
|
-
};
|
|
86
|
-
readonly type: {
|
|
87
|
-
readonly type: "String";
|
|
88
|
-
};
|
|
89
|
-
readonly message: {
|
|
90
|
-
readonly type: "String";
|
|
91
|
-
readonly nativeType: "Text";
|
|
92
|
-
};
|
|
93
|
-
readonly status: {
|
|
94
|
-
readonly type: "String";
|
|
95
|
-
readonly default: "\"open\"";
|
|
96
|
-
};
|
|
97
|
-
readonly url: {
|
|
98
|
-
readonly type: "String";
|
|
99
|
-
};
|
|
100
|
-
readonly urlPattern: {
|
|
101
|
-
readonly type: "String";
|
|
102
|
-
readonly optional: true;
|
|
103
|
-
};
|
|
104
|
-
readonly screenshotUrl: {
|
|
105
|
-
readonly type: "String";
|
|
106
|
-
readonly optional: true;
|
|
107
|
-
readonly nativeType: "Text";
|
|
108
|
-
};
|
|
109
|
-
readonly screenshotRegion: {
|
|
110
|
-
readonly type: "Json";
|
|
111
|
-
readonly optional: true;
|
|
112
|
-
};
|
|
113
|
-
readonly diagnostics: {
|
|
114
|
-
readonly type: "Json";
|
|
115
|
-
readonly optional: true;
|
|
116
|
-
};
|
|
117
|
-
readonly viewport: {
|
|
118
|
-
readonly type: "String";
|
|
119
|
-
};
|
|
120
|
-
readonly userAgent: {
|
|
121
|
-
readonly type: "String";
|
|
122
|
-
};
|
|
123
|
-
readonly authorName: {
|
|
124
|
-
readonly type: "String";
|
|
125
|
-
};
|
|
126
|
-
readonly authorEmail: {
|
|
127
|
-
readonly type: "String";
|
|
128
|
-
};
|
|
129
|
-
readonly clientId: {
|
|
130
|
-
readonly type: "String";
|
|
131
|
-
readonly isUnique: true;
|
|
132
|
-
};
|
|
133
|
-
readonly resolvedAt: {
|
|
134
|
-
readonly type: "DateTime";
|
|
135
|
-
readonly optional: true;
|
|
136
|
-
};
|
|
137
|
-
readonly createdAt: {
|
|
138
|
-
readonly type: "DateTime";
|
|
139
|
-
readonly default: "now()";
|
|
140
|
-
};
|
|
141
|
-
readonly updatedAt: {
|
|
142
|
-
readonly type: "DateTime";
|
|
143
|
-
readonly isUpdatedAt: true;
|
|
144
|
-
};
|
|
145
|
-
readonly annotations: {
|
|
146
|
-
readonly type: "SitepingAnnotation";
|
|
147
|
-
readonly relation: {
|
|
148
|
-
readonly kind: "1-to-many";
|
|
149
|
-
readonly model: "SitepingAnnotation";
|
|
150
|
-
};
|
|
151
|
-
};
|
|
152
|
-
};
|
|
153
|
-
readonly indexes: readonly [{
|
|
154
|
-
readonly fields: readonly ["projectName"];
|
|
155
|
-
}, {
|
|
156
|
-
readonly fields: readonly ["projectName", "status", "createdAt"];
|
|
157
|
-
}, {
|
|
158
|
-
readonly fields: readonly ["projectName", "url"];
|
|
159
|
-
}];
|
|
160
|
-
};
|
|
161
|
-
readonly SitepingAnnotation: {
|
|
162
|
-
readonly fields: {
|
|
163
|
-
readonly id: {
|
|
164
|
-
readonly type: "String";
|
|
165
|
-
readonly isId: true;
|
|
166
|
-
readonly default: "cuid()";
|
|
167
|
-
};
|
|
168
|
-
readonly feedbackId: {
|
|
169
|
-
readonly type: "String";
|
|
170
|
-
};
|
|
171
|
-
readonly feedback: {
|
|
172
|
-
readonly type: "SitepingFeedback";
|
|
173
|
-
readonly relation: {
|
|
174
|
-
readonly kind: "many-to-1";
|
|
175
|
-
readonly model: "SitepingFeedback";
|
|
176
|
-
readonly fields: readonly ["feedbackId"];
|
|
177
|
-
readonly references: readonly ["id"];
|
|
178
|
-
readonly onDelete: "Cascade";
|
|
179
|
-
};
|
|
180
|
-
};
|
|
181
|
-
readonly cssSelector: {
|
|
182
|
-
readonly type: "String";
|
|
183
|
-
readonly nativeType: "Text";
|
|
184
|
-
};
|
|
185
|
-
readonly xpath: {
|
|
186
|
-
readonly type: "String";
|
|
187
|
-
readonly nativeType: "Text";
|
|
188
|
-
};
|
|
189
|
-
readonly textSnippet: {
|
|
190
|
-
readonly type: "String";
|
|
191
|
-
readonly nativeType: "Text";
|
|
192
|
-
};
|
|
193
|
-
readonly elementTag: {
|
|
194
|
-
readonly type: "String";
|
|
195
|
-
};
|
|
196
|
-
readonly elementId: {
|
|
197
|
-
readonly type: "String";
|
|
198
|
-
readonly optional: true;
|
|
199
|
-
};
|
|
200
|
-
readonly textPrefix: {
|
|
201
|
-
readonly type: "String";
|
|
202
|
-
readonly nativeType: "Text";
|
|
203
|
-
};
|
|
204
|
-
readonly textSuffix: {
|
|
205
|
-
readonly type: "String";
|
|
206
|
-
readonly nativeType: "Text";
|
|
207
|
-
};
|
|
208
|
-
readonly fingerprint: {
|
|
209
|
-
readonly type: "String";
|
|
210
|
-
};
|
|
211
|
-
readonly neighborText: {
|
|
212
|
-
readonly type: "String";
|
|
213
|
-
readonly nativeType: "Text";
|
|
214
|
-
};
|
|
215
|
-
readonly anchorKey: {
|
|
216
|
-
readonly type: "String";
|
|
217
|
-
readonly optional: true;
|
|
218
|
-
};
|
|
219
|
-
readonly xPct: {
|
|
220
|
-
readonly type: "Float";
|
|
221
|
-
};
|
|
222
|
-
readonly yPct: {
|
|
223
|
-
readonly type: "Float";
|
|
224
|
-
};
|
|
225
|
-
readonly wPct: {
|
|
226
|
-
readonly type: "Float";
|
|
227
|
-
};
|
|
228
|
-
readonly hPct: {
|
|
229
|
-
readonly type: "Float";
|
|
230
|
-
};
|
|
231
|
-
readonly scrollX: {
|
|
232
|
-
readonly type: "Float";
|
|
233
|
-
};
|
|
234
|
-
readonly scrollY: {
|
|
235
|
-
readonly type: "Float";
|
|
236
|
-
};
|
|
237
|
-
readonly viewportW: {
|
|
238
|
-
readonly type: "Int";
|
|
239
|
-
};
|
|
240
|
-
readonly viewportH: {
|
|
241
|
-
readonly type: "Int";
|
|
242
|
-
};
|
|
243
|
-
readonly devicePixelRatio: {
|
|
244
|
-
readonly type: "Float";
|
|
245
|
-
readonly default: "1";
|
|
246
|
-
};
|
|
247
|
-
readonly createdAt: {
|
|
248
|
-
readonly type: "DateTime";
|
|
249
|
-
readonly default: "now()";
|
|
250
|
-
};
|
|
251
|
-
};
|
|
252
|
-
readonly indexes: readonly [{
|
|
253
|
-
readonly fields: readonly ["feedbackId"];
|
|
254
|
-
}];
|
|
255
|
-
};
|
|
256
|
-
};
|
|
257
|
-
/** Map of Siteping models keyed by model name — frozen at runtime. */
|
|
258
|
-
export declare const SITEPING_MODELS: typeof _SITEPING_MODELS;
|
|
259
|
-
/** Union of every Siteping model name as a string literal. */
|
|
260
|
-
export type SitepingModelName = keyof typeof SITEPING_MODELS;
|
|
261
|
-
/** Field names declared on a specific Siteping model. */
|
|
262
|
-
export type SitepingModelFieldName<M extends SitepingModelName> = keyof (typeof SITEPING_MODELS)[M]["fields"];
|
|
263
|
-
export {};
|
|
76
|
+
export { BEEZPING_MODELS } from "./constants/schema.cjs";
|
|
77
|
+
/** Union of every Beezping model name as a string literal. */
|
|
78
|
+
export type BeezpingModelName = "BeezpingFeedback" | "BeezpingAnnotation" | "BeezpingComment";
|
|
79
|
+
/** Field names declared on a specific Beezping model. */
|
|
80
|
+
export type BeezpingModelFieldName<M extends BeezpingModelName> = keyof (typeof BEEZPING_MODELS)[M]["fields"];
|
package/dist/schema.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Beezping database models — single source of truth.
|
|
3
3
|
*
|
|
4
4
|
* Used by:
|
|
5
5
|
* - CLI to generate Prisma schema (via prisma-ast)
|
|
@@ -9,11 +9,12 @@
|
|
|
9
9
|
* This is a TS representation, NOT a .prisma file.
|
|
10
10
|
* The CLI generates the actual Prisma schema from this definition.
|
|
11
11
|
*/
|
|
12
|
-
|
|
12
|
+
import type { BEEZPING_MODELS } from "./constants/schema.js";
|
|
13
|
+
/** Prisma scalar types supported by Beezping field definitions. */
|
|
13
14
|
export type PrismaScalarType = "String" | "Boolean" | "Int" | "BigInt" | "Float" | "Decimal" | "DateTime" | "Json" | "Bytes";
|
|
14
15
|
/** Prisma native column hints applied via `@db.<NativeType>`. */
|
|
15
16
|
export type PrismaNativeType = "Text" | "VarChar" | "Char" | "MediumText" | "LongText" | (string & {});
|
|
16
|
-
/** Relation cardinality between two
|
|
17
|
+
/** Relation cardinality between two Beezping models. */
|
|
17
18
|
export type RelationKind = "1-to-many" | "many-to-1";
|
|
18
19
|
/** Prisma `onDelete` referential action. */
|
|
19
20
|
export type RelationOnDelete = "Cascade" | "Restrict" | "NoAction" | "SetNull" | "SetDefault";
|
|
@@ -33,7 +34,7 @@ export interface RelationDef {
|
|
|
33
34
|
onDelete?: RelationOnDelete;
|
|
34
35
|
}
|
|
35
36
|
/**
|
|
36
|
-
* Definition of a single field in a
|
|
37
|
+
* Definition of a single field in a Beezping database model.
|
|
37
38
|
*
|
|
38
39
|
* The interface intentionally keeps a wide structural shape so it stays
|
|
39
40
|
* easy to extend, but consumers can narrow via {@link isRelationField} /
|
|
@@ -63,201 +64,17 @@ export declare function isRelationField(field: FieldDef): field is FieldDef & {
|
|
|
63
64
|
export declare function isScalarField(field: FieldDef): field is FieldDef & {
|
|
64
65
|
relation?: undefined;
|
|
65
66
|
};
|
|
66
|
-
/** Definition of a composite index on a
|
|
67
|
+
/** Definition of a composite index on a Beezping database model. */
|
|
67
68
|
export interface IndexDef {
|
|
68
69
|
fields: readonly string[];
|
|
69
70
|
}
|
|
70
|
-
/** Definition of a single
|
|
71
|
+
/** Definition of a single Beezping database model (fields + indexes). */
|
|
71
72
|
export interface ModelDef {
|
|
72
73
|
fields: Record<string, FieldDef>;
|
|
73
74
|
indexes?: readonly IndexDef[];
|
|
74
75
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
readonly isId: true;
|
|
81
|
-
readonly default: "cuid()";
|
|
82
|
-
};
|
|
83
|
-
readonly projectName: {
|
|
84
|
-
readonly type: "String";
|
|
85
|
-
};
|
|
86
|
-
readonly type: {
|
|
87
|
-
readonly type: "String";
|
|
88
|
-
};
|
|
89
|
-
readonly message: {
|
|
90
|
-
readonly type: "String";
|
|
91
|
-
readonly nativeType: "Text";
|
|
92
|
-
};
|
|
93
|
-
readonly status: {
|
|
94
|
-
readonly type: "String";
|
|
95
|
-
readonly default: "\"open\"";
|
|
96
|
-
};
|
|
97
|
-
readonly url: {
|
|
98
|
-
readonly type: "String";
|
|
99
|
-
};
|
|
100
|
-
readonly urlPattern: {
|
|
101
|
-
readonly type: "String";
|
|
102
|
-
readonly optional: true;
|
|
103
|
-
};
|
|
104
|
-
readonly screenshotUrl: {
|
|
105
|
-
readonly type: "String";
|
|
106
|
-
readonly optional: true;
|
|
107
|
-
readonly nativeType: "Text";
|
|
108
|
-
};
|
|
109
|
-
readonly screenshotRegion: {
|
|
110
|
-
readonly type: "Json";
|
|
111
|
-
readonly optional: true;
|
|
112
|
-
};
|
|
113
|
-
readonly diagnostics: {
|
|
114
|
-
readonly type: "Json";
|
|
115
|
-
readonly optional: true;
|
|
116
|
-
};
|
|
117
|
-
readonly viewport: {
|
|
118
|
-
readonly type: "String";
|
|
119
|
-
};
|
|
120
|
-
readonly userAgent: {
|
|
121
|
-
readonly type: "String";
|
|
122
|
-
};
|
|
123
|
-
readonly authorName: {
|
|
124
|
-
readonly type: "String";
|
|
125
|
-
};
|
|
126
|
-
readonly authorEmail: {
|
|
127
|
-
readonly type: "String";
|
|
128
|
-
};
|
|
129
|
-
readonly clientId: {
|
|
130
|
-
readonly type: "String";
|
|
131
|
-
readonly isUnique: true;
|
|
132
|
-
};
|
|
133
|
-
readonly resolvedAt: {
|
|
134
|
-
readonly type: "DateTime";
|
|
135
|
-
readonly optional: true;
|
|
136
|
-
};
|
|
137
|
-
readonly createdAt: {
|
|
138
|
-
readonly type: "DateTime";
|
|
139
|
-
readonly default: "now()";
|
|
140
|
-
};
|
|
141
|
-
readonly updatedAt: {
|
|
142
|
-
readonly type: "DateTime";
|
|
143
|
-
readonly isUpdatedAt: true;
|
|
144
|
-
};
|
|
145
|
-
readonly annotations: {
|
|
146
|
-
readonly type: "SitepingAnnotation";
|
|
147
|
-
readonly relation: {
|
|
148
|
-
readonly kind: "1-to-many";
|
|
149
|
-
readonly model: "SitepingAnnotation";
|
|
150
|
-
};
|
|
151
|
-
};
|
|
152
|
-
};
|
|
153
|
-
readonly indexes: readonly [{
|
|
154
|
-
readonly fields: readonly ["projectName"];
|
|
155
|
-
}, {
|
|
156
|
-
readonly fields: readonly ["projectName", "status", "createdAt"];
|
|
157
|
-
}, {
|
|
158
|
-
readonly fields: readonly ["projectName", "url"];
|
|
159
|
-
}];
|
|
160
|
-
};
|
|
161
|
-
readonly SitepingAnnotation: {
|
|
162
|
-
readonly fields: {
|
|
163
|
-
readonly id: {
|
|
164
|
-
readonly type: "String";
|
|
165
|
-
readonly isId: true;
|
|
166
|
-
readonly default: "cuid()";
|
|
167
|
-
};
|
|
168
|
-
readonly feedbackId: {
|
|
169
|
-
readonly type: "String";
|
|
170
|
-
};
|
|
171
|
-
readonly feedback: {
|
|
172
|
-
readonly type: "SitepingFeedback";
|
|
173
|
-
readonly relation: {
|
|
174
|
-
readonly kind: "many-to-1";
|
|
175
|
-
readonly model: "SitepingFeedback";
|
|
176
|
-
readonly fields: readonly ["feedbackId"];
|
|
177
|
-
readonly references: readonly ["id"];
|
|
178
|
-
readonly onDelete: "Cascade";
|
|
179
|
-
};
|
|
180
|
-
};
|
|
181
|
-
readonly cssSelector: {
|
|
182
|
-
readonly type: "String";
|
|
183
|
-
readonly nativeType: "Text";
|
|
184
|
-
};
|
|
185
|
-
readonly xpath: {
|
|
186
|
-
readonly type: "String";
|
|
187
|
-
readonly nativeType: "Text";
|
|
188
|
-
};
|
|
189
|
-
readonly textSnippet: {
|
|
190
|
-
readonly type: "String";
|
|
191
|
-
readonly nativeType: "Text";
|
|
192
|
-
};
|
|
193
|
-
readonly elementTag: {
|
|
194
|
-
readonly type: "String";
|
|
195
|
-
};
|
|
196
|
-
readonly elementId: {
|
|
197
|
-
readonly type: "String";
|
|
198
|
-
readonly optional: true;
|
|
199
|
-
};
|
|
200
|
-
readonly textPrefix: {
|
|
201
|
-
readonly type: "String";
|
|
202
|
-
readonly nativeType: "Text";
|
|
203
|
-
};
|
|
204
|
-
readonly textSuffix: {
|
|
205
|
-
readonly type: "String";
|
|
206
|
-
readonly nativeType: "Text";
|
|
207
|
-
};
|
|
208
|
-
readonly fingerprint: {
|
|
209
|
-
readonly type: "String";
|
|
210
|
-
};
|
|
211
|
-
readonly neighborText: {
|
|
212
|
-
readonly type: "String";
|
|
213
|
-
readonly nativeType: "Text";
|
|
214
|
-
};
|
|
215
|
-
readonly anchorKey: {
|
|
216
|
-
readonly type: "String";
|
|
217
|
-
readonly optional: true;
|
|
218
|
-
};
|
|
219
|
-
readonly xPct: {
|
|
220
|
-
readonly type: "Float";
|
|
221
|
-
};
|
|
222
|
-
readonly yPct: {
|
|
223
|
-
readonly type: "Float";
|
|
224
|
-
};
|
|
225
|
-
readonly wPct: {
|
|
226
|
-
readonly type: "Float";
|
|
227
|
-
};
|
|
228
|
-
readonly hPct: {
|
|
229
|
-
readonly type: "Float";
|
|
230
|
-
};
|
|
231
|
-
readonly scrollX: {
|
|
232
|
-
readonly type: "Float";
|
|
233
|
-
};
|
|
234
|
-
readonly scrollY: {
|
|
235
|
-
readonly type: "Float";
|
|
236
|
-
};
|
|
237
|
-
readonly viewportW: {
|
|
238
|
-
readonly type: "Int";
|
|
239
|
-
};
|
|
240
|
-
readonly viewportH: {
|
|
241
|
-
readonly type: "Int";
|
|
242
|
-
};
|
|
243
|
-
readonly devicePixelRatio: {
|
|
244
|
-
readonly type: "Float";
|
|
245
|
-
readonly default: "1";
|
|
246
|
-
};
|
|
247
|
-
readonly createdAt: {
|
|
248
|
-
readonly type: "DateTime";
|
|
249
|
-
readonly default: "now()";
|
|
250
|
-
};
|
|
251
|
-
};
|
|
252
|
-
readonly indexes: readonly [{
|
|
253
|
-
readonly fields: readonly ["feedbackId"];
|
|
254
|
-
}];
|
|
255
|
-
};
|
|
256
|
-
};
|
|
257
|
-
/** Map of Siteping models keyed by model name — frozen at runtime. */
|
|
258
|
-
export declare const SITEPING_MODELS: typeof _SITEPING_MODELS;
|
|
259
|
-
/** Union of every Siteping model name as a string literal. */
|
|
260
|
-
export type SitepingModelName = keyof typeof SITEPING_MODELS;
|
|
261
|
-
/** Field names declared on a specific Siteping model. */
|
|
262
|
-
export type SitepingModelFieldName<M extends SitepingModelName> = keyof (typeof SITEPING_MODELS)[M]["fields"];
|
|
263
|
-
export {};
|
|
76
|
+
export { BEEZPING_MODELS } from "./constants/schema.js";
|
|
77
|
+
/** Union of every Beezping model name as a string literal. */
|
|
78
|
+
export type BeezpingModelName = "BeezpingFeedback" | "BeezpingAnnotation" | "BeezpingComment";
|
|
79
|
+
/** Field names declared on a specific Beezping model. */
|
|
80
|
+
export type BeezpingModelFieldName<M extends BeezpingModelName> = keyof (typeof BEEZPING_MODELS)[M]["fields"];
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pluggable storage for feedback screenshots.
|
|
3
3
|
*
|
|
4
|
-
* `adapter-prisma`
|
|
5
|
-
* provided, the adapter forwards the
|
|
6
|
-
* and persists the returned URL on
|
|
7
|
-
* provided, the adapter falls back to
|
|
8
|
-
*
|
|
4
|
+
* `adapter-prisma` and `adapter-drizzle` accept an optional
|
|
5
|
+
* `screenshotStorage` config. When provided, the adapter forwards the
|
|
6
|
+
* widget-supplied data URL to `upload()` and persists the returned URL on
|
|
7
|
+
* `Feedback.screenshotUrl`. When not provided, the adapter falls back to
|
|
8
|
+
* inline base64 (with a one-time warn) — fine for dev and small
|
|
9
|
+
* deployments, a footgun for production Postgres.
|
|
9
10
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* `@beezping/screenshot-storage` implements it over any S3-compatible
|
|
12
|
+
* bucket (AWS S3, Cloudflare R2, Backblaze B2, MinIO…), Cloudflare Images,
|
|
13
|
+
* a database table, the local filesystem or memory. Implement it yourself
|
|
14
|
+
* for anything else.
|
|
14
15
|
*
|
|
15
16
|
* @example
|
|
16
17
|
* ```ts
|
|
@@ -19,17 +20,17 @@
|
|
|
19
20
|
*
|
|
20
21
|
* const s3 = new S3Client({ region: "eu-west-3" });
|
|
21
22
|
* const screenshotStorage: ScreenshotStorage = {
|
|
22
|
-
* async upload(dataUrl,
|
|
23
|
-
* const
|
|
24
|
-
* const key = `
|
|
23
|
+
* async upload(dataUrl, { mimeType }) {
|
|
24
|
+
* const body = Buffer.from(dataUrl.slice(dataUrl.indexOf(",") + 1), "base64");
|
|
25
|
+
* const key = `beezping/${crypto.randomUUID()}`; // fresh per upload, see URL ownership
|
|
25
26
|
* await s3.send(new PutObjectCommand({
|
|
26
|
-
* Bucket: "my-bucket", Key: key, Body:
|
|
27
|
+
* Bucket: "my-bucket", Key: key, Body: body, ContentType: mimeType,
|
|
27
28
|
* }));
|
|
28
29
|
* return { url: `https://cdn.example.com/${key}` };
|
|
29
30
|
* },
|
|
30
31
|
* };
|
|
31
32
|
*
|
|
32
|
-
*
|
|
33
|
+
* createBeezpingHandler({ prisma, screenshotStorage });
|
|
33
34
|
* ```
|
|
34
35
|
*/
|
|
35
36
|
export interface ScreenshotStorage {
|
|
@@ -44,17 +45,19 @@ export interface ScreenshotStorage {
|
|
|
44
45
|
* `ctx.feedbackId` identifies the upload. Adapters that upload before the
|
|
45
46
|
* record exists pass the *client-generated* `clientId` (Prisma); the
|
|
46
47
|
* Drizzle adapter passes the server-generated id the create attempt will
|
|
47
|
-
* insert the record under
|
|
48
|
-
* one `clientId` never write the same object key.
|
|
48
|
+
* insert the record under.
|
|
49
49
|
*
|
|
50
|
-
* **URL ownership:**
|
|
51
|
-
* key the object by
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
50
|
+
* **URL ownership:** every call must return a URL no other call returns —
|
|
51
|
+
* key the object by a fresh random value (`crypto.randomUUID()`, as the
|
|
52
|
+
* example does), never by `ctx.feedbackId` alone nor by a content hash.
|
|
53
|
+
* Adapters treat each URL as the property of the one record that stores it
|
|
54
|
+
* and may pass it to `delete` once that record is deleted, or once its
|
|
55
|
+
* create lost a race: two submissions of one `clientId` both upload, and
|
|
56
|
+
* the object of the one that is not stored is deleted. Under Prisma,
|
|
57
|
+
* `ctx.feedbackId` is that client-supplied `clientId`, so an object keyed
|
|
58
|
+
* by it is rewritten by every replay — a retry, or anyone who learns the
|
|
59
|
+
* id — and a URL shared by several records lets deleting one remove the
|
|
60
|
+
* object another still points at.
|
|
58
61
|
*
|
|
59
62
|
* **Security note:** treat `ctx.feedbackId` as attacker-controlled:
|
|
60
63
|
* sanitize before using it in filesystem paths or object keys, even though
|
|
@@ -67,12 +70,34 @@ export interface ScreenshotStorage {
|
|
|
67
70
|
url: string;
|
|
68
71
|
}>;
|
|
69
72
|
/**
|
|
70
|
-
* Optional cleanup hook called when the feedback is deleted,
|
|
71
|
-
* uploaded
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
73
|
+
* Optional cleanup hook called when the feedback is deleted, and for an
|
|
74
|
+
* object uploaded by a create whose record was not stored: one rejected
|
|
75
|
+
* because its `clientId` is already stored, or — in adapters that key
|
|
76
|
+
* uploads per attempt, like Drizzle — one whose insert failed. An object a
|
|
77
|
+
* stored row still references (a deterministic key reused by the replay)
|
|
78
|
+
* is kept. Receives only URLs returned by {@link ScreenshotStorage.upload}.
|
|
79
|
+
* Adapters call this best-effort and swallow errors — orphaned objects are
|
|
80
|
+
* preferred over failed deletes.
|
|
76
81
|
*/
|
|
77
82
|
delete?: (url: string) => Promise<void>;
|
|
78
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Most `ScreenshotStorage.delete` calls one cleanup keeps in flight — a
|
|
86
|
+
* project delete may free thousands of objects, and firing them all at once
|
|
87
|
+
* can exhaust sockets (one per request with `fetch`) or memory and trip
|
|
88
|
+
* object-store rate limits. It stays under the 50 sockets the AWS SDK opens
|
|
89
|
+
* per client by default, yet a project delete, which waits for its cleanup,
|
|
90
|
+
* is not serialised: 1,000 objects take 32 rounds. Adapters run their
|
|
91
|
+
* deletes through `settleWithConcurrencyLimit` with this bound.
|
|
92
|
+
*/
|
|
93
|
+
export declare const SCREENSHOT_DELETE_CONCURRENCY = 32;
|
|
94
|
+
/**
|
|
95
|
+
* MIME type an adapter reports to {@link ScreenshotStorage.upload}: the one
|
|
96
|
+
* an image data URL declares (`data:image/png;base64,…` → `image/png`),
|
|
97
|
+
* limited to the JPEG, PNG and WebP the HTTP schema accepts. Stores are
|
|
98
|
+
* public and may be fed unvalidated data URLs, and an `image/svg+xml` label
|
|
99
|
+
* would make the stored object script-capable when served inline. Anything
|
|
100
|
+
* else — including a data URL that declares no type — reports JPEG, the
|
|
101
|
+
* widget's capture format.
|
|
102
|
+
*/
|
|
103
|
+
export declare function screenshotMimeType(dataUrl: string): string;
|