@siteping/server 0.1.0 → 0.2.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 +1 -1
- package/dist/deep-link.d.cts +10 -0
- package/dist/deep-link.d.ts +10 -0
- package/dist/errors.d.cts +46 -16
- package/dist/errors.d.ts +46 -16
- package/dist/i18n.d.cts +14 -10
- package/dist/i18n.d.ts +14 -10
- package/dist/index.cjs +536 -259
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +156 -71
- package/dist/index.d.ts +156 -71
- package/dist/index.js +536 -259
- package/dist/index.js.map +1 -1
- package/dist/logger.d.cts +30 -0
- package/dist/logger.d.ts +30 -0
- package/dist/schema.d.cts +31 -0
- package/dist/schema.d.ts +31 -0
- package/dist/screenshot-storage.d.cts +14 -17
- package/dist/screenshot-storage.d.ts +14 -17
- package/dist/siteping-core.d.cts +8 -5
- package/dist/siteping-core.d.ts +8 -5
- package/dist/store-helpers.d.cts +13 -9
- package/dist/store-helpers.d.ts +13 -9
- package/dist/text.d.cts +28 -0
- package/dist/text.d.ts +28 -0
- package/dist/types.d.cts +116 -39
- package/dist/types.d.ts +116 -39
- package/dist/wire.d.cts +6 -1
- package/dist/wire.d.ts +6 -1
- package/openapi.json +1532 -0
- package/package.json +7 -5
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where SitePing reports what goes wrong. The arguments come in console's and
|
|
3
|
+
* winston's order, so `console` and winston satisfy it as they are. pino's
|
|
4
|
+
* methods take the context first and type-check here anyway, then drop the
|
|
5
|
+
* context: adapt them — `{ error: (message, { error, ...context }) =>
|
|
6
|
+
* log.error({ err: error, ...context }, message), warn: … }`.
|
|
7
|
+
*
|
|
8
|
+
* Each option asks only for the level it reports — the handler's `logger`
|
|
9
|
+
* for `error`, the stores' and screenshot storages' for `warn`
|
|
10
|
+
* ({@link SitepingWarnLogger}) — so one object can be handed to all of them.
|
|
11
|
+
*/
|
|
12
|
+
export interface SitepingLogger {
|
|
13
|
+
/** Unexpected failures: a request answered 500, a hook or a lookup failed. */
|
|
14
|
+
error(message: string, context: Record<string, unknown>): void | Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Degraded but handled: a screenshot dropped or left orphaned, screenshots
|
|
17
|
+
* stored inline. The handler never calls it; the stores and screenshot
|
|
18
|
+
* storages require it.
|
|
19
|
+
*/
|
|
20
|
+
warn?(message: string, context: Record<string, unknown>): void | Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
/** What the stores and screenshot storages report through: a {@link SitepingLogger} with `warn`. */
|
|
23
|
+
export type SitepingWarnLogger = Required<Pick<SitepingLogger, "warn">>;
|
|
24
|
+
/**
|
|
25
|
+
* Report through `logger.warn` without letting the logger fail its caller,
|
|
26
|
+
* on paths documented as non-throwing: a throw, or a rejection of what it
|
|
27
|
+
* returns — unhandled, fatal in Node by default — is dropped. A broken
|
|
28
|
+
* logger has no other channel to report through.
|
|
29
|
+
*/
|
|
30
|
+
export declare function warnSafely(logger: SitepingWarnLogger, message: string, context: Record<string, unknown>): void;
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where SitePing reports what goes wrong. The arguments come in console's and
|
|
3
|
+
* winston's order, so `console` and winston satisfy it as they are. pino's
|
|
4
|
+
* methods take the context first and type-check here anyway, then drop the
|
|
5
|
+
* context: adapt them — `{ error: (message, { error, ...context }) =>
|
|
6
|
+
* log.error({ err: error, ...context }, message), warn: … }`.
|
|
7
|
+
*
|
|
8
|
+
* Each option asks only for the level it reports — the handler's `logger`
|
|
9
|
+
* for `error`, the stores' and screenshot storages' for `warn`
|
|
10
|
+
* ({@link SitepingWarnLogger}) — so one object can be handed to all of them.
|
|
11
|
+
*/
|
|
12
|
+
export interface SitepingLogger {
|
|
13
|
+
/** Unexpected failures: a request answered 500, a hook or a lookup failed. */
|
|
14
|
+
error(message: string, context: Record<string, unknown>): void | Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Degraded but handled: a screenshot dropped or left orphaned, screenshots
|
|
17
|
+
* stored inline. The handler never calls it; the stores and screenshot
|
|
18
|
+
* storages require it.
|
|
19
|
+
*/
|
|
20
|
+
warn?(message: string, context: Record<string, unknown>): void | Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
/** What the stores and screenshot storages report through: a {@link SitepingLogger} with `warn`. */
|
|
23
|
+
export type SitepingWarnLogger = Required<Pick<SitepingLogger, "warn">>;
|
|
24
|
+
/**
|
|
25
|
+
* Report through `logger.warn` without letting the logger fail its caller,
|
|
26
|
+
* on paths documented as non-throwing: a throw, or a rejection of what it
|
|
27
|
+
* returns — unhandled, fatal in Node by default — is dropped. A broken
|
|
28
|
+
* logger has no other channel to report through.
|
|
29
|
+
*/
|
|
30
|
+
export declare function warnSafely(logger: SitepingWarnLogger, message: string, context: Record<string, unknown>): void;
|
package/dist/schema.d.cts
CHANGED
|
@@ -52,6 +52,13 @@ export interface FieldDef {
|
|
|
52
52
|
isUnique?: boolean;
|
|
53
53
|
/** Prisma native type attribute (e.g. "Text" for @db.Text) — used for MySQL compatibility on long strings */
|
|
54
54
|
nativeType?: PrismaNativeType;
|
|
55
|
+
/**
|
|
56
|
+
* Longest value the HTTP handler accepts for this column, in characters —
|
|
57
|
+
* set on every `String` column filled from a request body, and checked
|
|
58
|
+
* against the handler's own caps. The CLI sizes the column from it where a
|
|
59
|
+
* plain `String` is shorter: on MySQL, a `VARCHAR(191)`.
|
|
60
|
+
*/
|
|
61
|
+
maxLength?: number;
|
|
55
62
|
/** Prisma @updatedAt attribute */
|
|
56
63
|
isUpdatedAt?: boolean;
|
|
57
64
|
}
|
|
@@ -82,6 +89,7 @@ declare const _SITEPING_MODELS: {
|
|
|
82
89
|
};
|
|
83
90
|
readonly projectName: {
|
|
84
91
|
readonly type: "String";
|
|
92
|
+
readonly maxLength: 191;
|
|
85
93
|
};
|
|
86
94
|
readonly type: {
|
|
87
95
|
readonly type: "String";
|
|
@@ -89,6 +97,7 @@ declare const _SITEPING_MODELS: {
|
|
|
89
97
|
readonly message: {
|
|
90
98
|
readonly type: "String";
|
|
91
99
|
readonly nativeType: "Text";
|
|
100
|
+
readonly maxLength: 5000;
|
|
92
101
|
};
|
|
93
102
|
readonly status: {
|
|
94
103
|
readonly type: "String";
|
|
@@ -96,15 +105,18 @@ declare const _SITEPING_MODELS: {
|
|
|
96
105
|
};
|
|
97
106
|
readonly url: {
|
|
98
107
|
readonly type: "String";
|
|
108
|
+
readonly maxLength: 2000;
|
|
99
109
|
};
|
|
100
110
|
readonly urlPattern: {
|
|
101
111
|
readonly type: "String";
|
|
102
112
|
readonly optional: true;
|
|
113
|
+
readonly maxLength: 2000;
|
|
103
114
|
};
|
|
104
115
|
readonly screenshotUrl: {
|
|
105
116
|
readonly type: "String";
|
|
106
117
|
readonly optional: true;
|
|
107
118
|
readonly nativeType: "Text";
|
|
119
|
+
readonly maxLength: 1500000;
|
|
108
120
|
};
|
|
109
121
|
readonly screenshotRegion: {
|
|
110
122
|
readonly type: "Json";
|
|
@@ -116,19 +128,24 @@ declare const _SITEPING_MODELS: {
|
|
|
116
128
|
};
|
|
117
129
|
readonly viewport: {
|
|
118
130
|
readonly type: "String";
|
|
131
|
+
readonly maxLength: 50;
|
|
119
132
|
};
|
|
120
133
|
readonly userAgent: {
|
|
121
134
|
readonly type: "String";
|
|
135
|
+
readonly maxLength: 500;
|
|
122
136
|
};
|
|
123
137
|
readonly authorName: {
|
|
124
138
|
readonly type: "String";
|
|
139
|
+
readonly maxLength: 200;
|
|
125
140
|
};
|
|
126
141
|
readonly authorEmail: {
|
|
127
142
|
readonly type: "String";
|
|
143
|
+
readonly maxLength: 200;
|
|
128
144
|
};
|
|
129
145
|
readonly clientId: {
|
|
130
146
|
readonly type: "String";
|
|
131
147
|
readonly isUnique: true;
|
|
148
|
+
readonly maxLength: 191;
|
|
132
149
|
};
|
|
133
150
|
readonly resolvedAt: {
|
|
134
151
|
readonly type: "DateTime";
|
|
@@ -188,40 +205,50 @@ declare const _SITEPING_MODELS: {
|
|
|
188
205
|
readonly cssSelector: {
|
|
189
206
|
readonly type: "String";
|
|
190
207
|
readonly nativeType: "Text";
|
|
208
|
+
readonly maxLength: 2000;
|
|
191
209
|
};
|
|
192
210
|
readonly xpath: {
|
|
193
211
|
readonly type: "String";
|
|
194
212
|
readonly nativeType: "Text";
|
|
213
|
+
readonly maxLength: 2000;
|
|
195
214
|
};
|
|
196
215
|
readonly textSnippet: {
|
|
197
216
|
readonly type: "String";
|
|
198
217
|
readonly nativeType: "Text";
|
|
218
|
+
readonly maxLength: 500;
|
|
199
219
|
};
|
|
200
220
|
readonly elementTag: {
|
|
201
221
|
readonly type: "String";
|
|
222
|
+
readonly maxLength: 191;
|
|
202
223
|
};
|
|
203
224
|
readonly elementId: {
|
|
204
225
|
readonly type: "String";
|
|
205
226
|
readonly optional: true;
|
|
227
|
+
readonly maxLength: 191;
|
|
206
228
|
};
|
|
207
229
|
readonly textPrefix: {
|
|
208
230
|
readonly type: "String";
|
|
209
231
|
readonly nativeType: "Text";
|
|
232
|
+
readonly maxLength: 200;
|
|
210
233
|
};
|
|
211
234
|
readonly textSuffix: {
|
|
212
235
|
readonly type: "String";
|
|
213
236
|
readonly nativeType: "Text";
|
|
237
|
+
readonly maxLength: 200;
|
|
214
238
|
};
|
|
215
239
|
readonly fingerprint: {
|
|
216
240
|
readonly type: "String";
|
|
241
|
+
readonly maxLength: 200;
|
|
217
242
|
};
|
|
218
243
|
readonly neighborText: {
|
|
219
244
|
readonly type: "String";
|
|
220
245
|
readonly nativeType: "Text";
|
|
246
|
+
readonly maxLength: 500;
|
|
221
247
|
};
|
|
222
248
|
readonly anchorKey: {
|
|
223
249
|
readonly type: "String";
|
|
224
250
|
readonly optional: true;
|
|
251
|
+
readonly maxLength: 200;
|
|
225
252
|
};
|
|
226
253
|
readonly xPct: {
|
|
227
254
|
readonly type: "Float";
|
|
@@ -283,12 +310,15 @@ declare const _SITEPING_MODELS: {
|
|
|
283
310
|
readonly body: {
|
|
284
311
|
readonly type: "String";
|
|
285
312
|
readonly nativeType: "Text";
|
|
313
|
+
readonly maxLength: 5000;
|
|
286
314
|
};
|
|
287
315
|
readonly authorName: {
|
|
288
316
|
readonly type: "String";
|
|
317
|
+
readonly maxLength: 200;
|
|
289
318
|
};
|
|
290
319
|
readonly authorEmail: {
|
|
291
320
|
readonly type: "String";
|
|
321
|
+
readonly maxLength: 200;
|
|
292
322
|
};
|
|
293
323
|
readonly authorRole: {
|
|
294
324
|
readonly type: "String";
|
|
@@ -297,6 +327,7 @@ declare const _SITEPING_MODELS: {
|
|
|
297
327
|
readonly clientId: {
|
|
298
328
|
readonly type: "String";
|
|
299
329
|
readonly isUnique: true;
|
|
330
|
+
readonly maxLength: 191;
|
|
300
331
|
};
|
|
301
332
|
readonly createdAt: {
|
|
302
333
|
readonly type: "DateTime";
|
package/dist/schema.d.ts
CHANGED
|
@@ -52,6 +52,13 @@ export interface FieldDef {
|
|
|
52
52
|
isUnique?: boolean;
|
|
53
53
|
/** Prisma native type attribute (e.g. "Text" for @db.Text) — used for MySQL compatibility on long strings */
|
|
54
54
|
nativeType?: PrismaNativeType;
|
|
55
|
+
/**
|
|
56
|
+
* Longest value the HTTP handler accepts for this column, in characters —
|
|
57
|
+
* set on every `String` column filled from a request body, and checked
|
|
58
|
+
* against the handler's own caps. The CLI sizes the column from it where a
|
|
59
|
+
* plain `String` is shorter: on MySQL, a `VARCHAR(191)`.
|
|
60
|
+
*/
|
|
61
|
+
maxLength?: number;
|
|
55
62
|
/** Prisma @updatedAt attribute */
|
|
56
63
|
isUpdatedAt?: boolean;
|
|
57
64
|
}
|
|
@@ -82,6 +89,7 @@ declare const _SITEPING_MODELS: {
|
|
|
82
89
|
};
|
|
83
90
|
readonly projectName: {
|
|
84
91
|
readonly type: "String";
|
|
92
|
+
readonly maxLength: 191;
|
|
85
93
|
};
|
|
86
94
|
readonly type: {
|
|
87
95
|
readonly type: "String";
|
|
@@ -89,6 +97,7 @@ declare const _SITEPING_MODELS: {
|
|
|
89
97
|
readonly message: {
|
|
90
98
|
readonly type: "String";
|
|
91
99
|
readonly nativeType: "Text";
|
|
100
|
+
readonly maxLength: 5000;
|
|
92
101
|
};
|
|
93
102
|
readonly status: {
|
|
94
103
|
readonly type: "String";
|
|
@@ -96,15 +105,18 @@ declare const _SITEPING_MODELS: {
|
|
|
96
105
|
};
|
|
97
106
|
readonly url: {
|
|
98
107
|
readonly type: "String";
|
|
108
|
+
readonly maxLength: 2000;
|
|
99
109
|
};
|
|
100
110
|
readonly urlPattern: {
|
|
101
111
|
readonly type: "String";
|
|
102
112
|
readonly optional: true;
|
|
113
|
+
readonly maxLength: 2000;
|
|
103
114
|
};
|
|
104
115
|
readonly screenshotUrl: {
|
|
105
116
|
readonly type: "String";
|
|
106
117
|
readonly optional: true;
|
|
107
118
|
readonly nativeType: "Text";
|
|
119
|
+
readonly maxLength: 1500000;
|
|
108
120
|
};
|
|
109
121
|
readonly screenshotRegion: {
|
|
110
122
|
readonly type: "Json";
|
|
@@ -116,19 +128,24 @@ declare const _SITEPING_MODELS: {
|
|
|
116
128
|
};
|
|
117
129
|
readonly viewport: {
|
|
118
130
|
readonly type: "String";
|
|
131
|
+
readonly maxLength: 50;
|
|
119
132
|
};
|
|
120
133
|
readonly userAgent: {
|
|
121
134
|
readonly type: "String";
|
|
135
|
+
readonly maxLength: 500;
|
|
122
136
|
};
|
|
123
137
|
readonly authorName: {
|
|
124
138
|
readonly type: "String";
|
|
139
|
+
readonly maxLength: 200;
|
|
125
140
|
};
|
|
126
141
|
readonly authorEmail: {
|
|
127
142
|
readonly type: "String";
|
|
143
|
+
readonly maxLength: 200;
|
|
128
144
|
};
|
|
129
145
|
readonly clientId: {
|
|
130
146
|
readonly type: "String";
|
|
131
147
|
readonly isUnique: true;
|
|
148
|
+
readonly maxLength: 191;
|
|
132
149
|
};
|
|
133
150
|
readonly resolvedAt: {
|
|
134
151
|
readonly type: "DateTime";
|
|
@@ -188,40 +205,50 @@ declare const _SITEPING_MODELS: {
|
|
|
188
205
|
readonly cssSelector: {
|
|
189
206
|
readonly type: "String";
|
|
190
207
|
readonly nativeType: "Text";
|
|
208
|
+
readonly maxLength: 2000;
|
|
191
209
|
};
|
|
192
210
|
readonly xpath: {
|
|
193
211
|
readonly type: "String";
|
|
194
212
|
readonly nativeType: "Text";
|
|
213
|
+
readonly maxLength: 2000;
|
|
195
214
|
};
|
|
196
215
|
readonly textSnippet: {
|
|
197
216
|
readonly type: "String";
|
|
198
217
|
readonly nativeType: "Text";
|
|
218
|
+
readonly maxLength: 500;
|
|
199
219
|
};
|
|
200
220
|
readonly elementTag: {
|
|
201
221
|
readonly type: "String";
|
|
222
|
+
readonly maxLength: 191;
|
|
202
223
|
};
|
|
203
224
|
readonly elementId: {
|
|
204
225
|
readonly type: "String";
|
|
205
226
|
readonly optional: true;
|
|
227
|
+
readonly maxLength: 191;
|
|
206
228
|
};
|
|
207
229
|
readonly textPrefix: {
|
|
208
230
|
readonly type: "String";
|
|
209
231
|
readonly nativeType: "Text";
|
|
232
|
+
readonly maxLength: 200;
|
|
210
233
|
};
|
|
211
234
|
readonly textSuffix: {
|
|
212
235
|
readonly type: "String";
|
|
213
236
|
readonly nativeType: "Text";
|
|
237
|
+
readonly maxLength: 200;
|
|
214
238
|
};
|
|
215
239
|
readonly fingerprint: {
|
|
216
240
|
readonly type: "String";
|
|
241
|
+
readonly maxLength: 200;
|
|
217
242
|
};
|
|
218
243
|
readonly neighborText: {
|
|
219
244
|
readonly type: "String";
|
|
220
245
|
readonly nativeType: "Text";
|
|
246
|
+
readonly maxLength: 500;
|
|
221
247
|
};
|
|
222
248
|
readonly anchorKey: {
|
|
223
249
|
readonly type: "String";
|
|
224
250
|
readonly optional: true;
|
|
251
|
+
readonly maxLength: 200;
|
|
225
252
|
};
|
|
226
253
|
readonly xPct: {
|
|
227
254
|
readonly type: "Float";
|
|
@@ -283,12 +310,15 @@ declare const _SITEPING_MODELS: {
|
|
|
283
310
|
readonly body: {
|
|
284
311
|
readonly type: "String";
|
|
285
312
|
readonly nativeType: "Text";
|
|
313
|
+
readonly maxLength: 5000;
|
|
286
314
|
};
|
|
287
315
|
readonly authorName: {
|
|
288
316
|
readonly type: "String";
|
|
317
|
+
readonly maxLength: 200;
|
|
289
318
|
};
|
|
290
319
|
readonly authorEmail: {
|
|
291
320
|
readonly type: "String";
|
|
321
|
+
readonly maxLength: 200;
|
|
292
322
|
};
|
|
293
323
|
readonly authorRole: {
|
|
294
324
|
readonly type: "String";
|
|
@@ -297,6 +327,7 @@ declare const _SITEPING_MODELS: {
|
|
|
297
327
|
readonly clientId: {
|
|
298
328
|
readonly type: "String";
|
|
299
329
|
readonly isUnique: true;
|
|
330
|
+
readonly maxLength: 191;
|
|
300
331
|
};
|
|
301
332
|
readonly createdAt: {
|
|
302
333
|
readonly type: "DateTime";
|
|
@@ -42,26 +42,24 @@ export interface ScreenshotStorage {
|
|
|
42
42
|
* Adapters call this synchronously inside `createFeedback` — keep it
|
|
43
43
|
* fast or move to a queue if needed.
|
|
44
44
|
*
|
|
45
|
-
* `ctx.feedbackId`
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
45
|
+
* `ctx.feedbackId` is the id the feedback is stored under. The record does
|
|
46
|
+
* not exist yet, so the store draws it before the upload — fresh for each
|
|
47
|
+
* create attempt, never client-supplied — and inserts the row under it.
|
|
48
|
+
* Two submissions of one `clientId` therefore upload under two ids, and
|
|
49
|
+
* only one of them is stored.
|
|
49
50
|
*
|
|
50
51
|
* **URL ownership:** every call must return a URL no other call returns —
|
|
51
52
|
* key the object by a fresh random value (`crypto.randomUUID()`, as the
|
|
52
53
|
* example does), never by `ctx.feedbackId` alone nor by a content hash.
|
|
53
54
|
* Adapters treat each URL as the property of the one record that stores it
|
|
54
55
|
* and may pass it to `delete` once that record is deleted, or once its
|
|
55
|
-
* create lost a race:
|
|
56
|
-
*
|
|
57
|
-
*
|
|
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.
|
|
56
|
+
* create lost a race: the object of the submission that is not stored is
|
|
57
|
+
* deleted, and a URL shared by several records would let deleting one
|
|
58
|
+
* remove the object another still points at.
|
|
61
59
|
*
|
|
62
|
-
* **Security note:**
|
|
63
|
-
*
|
|
64
|
-
*
|
|
60
|
+
* **Security note:** the bundled stores generate `ctx.feedbackId`, but a
|
|
61
|
+
* third-party one may not honour the contract: sanitize it before using it
|
|
62
|
+
* in a filesystem path or an object key.
|
|
65
63
|
*/
|
|
66
64
|
upload(dataUrl: string, ctx: {
|
|
67
65
|
feedbackId: string;
|
|
@@ -72,10 +70,9 @@ export interface ScreenshotStorage {
|
|
|
72
70
|
/**
|
|
73
71
|
* Optional cleanup hook called when the feedback is deleted, and for an
|
|
74
72
|
* object uploaded by a create whose record was not stored: one rejected
|
|
75
|
-
* because its `clientId` is already stored, or
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* is kept. Receives only URLs returned by {@link ScreenshotStorage.upload}.
|
|
73
|
+
* because its `clientId` is already stored, or one whose insert failed. An
|
|
74
|
+
* object a stored row still references (a storage that broke URL
|
|
75
|
+
* ownership) is kept. Receives only URLs returned by {@link ScreenshotStorage.upload}.
|
|
79
76
|
* Adapters call this best-effort and swallow errors — orphaned objects are
|
|
80
77
|
* preferred over failed deletes.
|
|
81
78
|
*/
|
|
@@ -42,26 +42,24 @@ export interface ScreenshotStorage {
|
|
|
42
42
|
* Adapters call this synchronously inside `createFeedback` — keep it
|
|
43
43
|
* fast or move to a queue if needed.
|
|
44
44
|
*
|
|
45
|
-
* `ctx.feedbackId`
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
45
|
+
* `ctx.feedbackId` is the id the feedback is stored under. The record does
|
|
46
|
+
* not exist yet, so the store draws it before the upload — fresh for each
|
|
47
|
+
* create attempt, never client-supplied — and inserts the row under it.
|
|
48
|
+
* Two submissions of one `clientId` therefore upload under two ids, and
|
|
49
|
+
* only one of them is stored.
|
|
49
50
|
*
|
|
50
51
|
* **URL ownership:** every call must return a URL no other call returns —
|
|
51
52
|
* key the object by a fresh random value (`crypto.randomUUID()`, as the
|
|
52
53
|
* example does), never by `ctx.feedbackId` alone nor by a content hash.
|
|
53
54
|
* Adapters treat each URL as the property of the one record that stores it
|
|
54
55
|
* and may pass it to `delete` once that record is deleted, or once its
|
|
55
|
-
* create lost a race:
|
|
56
|
-
*
|
|
57
|
-
*
|
|
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.
|
|
56
|
+
* create lost a race: the object of the submission that is not stored is
|
|
57
|
+
* deleted, and a URL shared by several records would let deleting one
|
|
58
|
+
* remove the object another still points at.
|
|
61
59
|
*
|
|
62
|
-
* **Security note:**
|
|
63
|
-
*
|
|
64
|
-
*
|
|
60
|
+
* **Security note:** the bundled stores generate `ctx.feedbackId`, but a
|
|
61
|
+
* third-party one may not honour the contract: sanitize it before using it
|
|
62
|
+
* in a filesystem path or an object key.
|
|
65
63
|
*/
|
|
66
64
|
upload(dataUrl: string, ctx: {
|
|
67
65
|
feedbackId: string;
|
|
@@ -72,10 +70,9 @@ export interface ScreenshotStorage {
|
|
|
72
70
|
/**
|
|
73
71
|
* Optional cleanup hook called when the feedback is deleted, and for an
|
|
74
72
|
* object uploaded by a create whose record was not stored: one rejected
|
|
75
|
-
* because its `clientId` is already stored, or
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* is kept. Receives only URLs returned by {@link ScreenshotStorage.upload}.
|
|
73
|
+
* because its `clientId` is already stored, or one whose insert failed. An
|
|
74
|
+
* object a stored row still references (a storage that broke URL
|
|
75
|
+
* ownership) is kept. Receives only URLs returned by {@link ScreenshotStorage.upload}.
|
|
79
76
|
* Adapters call this best-effort and swallow errors — orphaned objects are
|
|
80
77
|
* preferred over failed deletes.
|
|
81
78
|
*/
|
package/dist/siteping-core.d.cts
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
export { settleWithConcurrencyLimit } from "./concurrency.cjs";
|
|
2
|
-
export { buildDeepLink, parseHttpUrl } from "./deep-link.cjs";
|
|
2
|
+
export { buildDeepLink, isSafeImageUrl, parseHttpUrl } from "./deep-link.cjs";
|
|
3
3
|
export { EMAIL_PATTERN, isValidEmail } from "./email.cjs";
|
|
4
|
-
export type { SitepingErrorCode } from "./errors.cjs";
|
|
5
|
-
export { SitepingAuthError, SitepingError, SitepingNetworkError, SitepingValidationError } from "./errors.cjs";
|
|
4
|
+
export type { SitepingClientError, SitepingConfigErrorCode, SitepingErrorCode } from "./errors.cjs";
|
|
5
|
+
export { isSitepingConfigError, isSitepingError, SitepingAuthError, SitepingConfigError, SitepingError, SitepingNetworkError, SitepingValidationError, } from "./errors.cjs";
|
|
6
6
|
export type { FilterResult, Pagination } from "./filters.cjs";
|
|
7
7
|
export { applyFeedbackFilters, clampPagination, DEFAULT_PAGE_LIMIT, isUnreachableOffset, MAX_PAGE_LIMIT, matchesFeedbackQuery, } from "./filters.cjs";
|
|
8
8
|
export type { I18n, LocaleLoaders, TranslateFunction } from "./i18n.cjs";
|
|
9
9
|
export { canonicalizeLocale, createI18n, interpolate, intlLocale, tWithParams } from "./i18n.cjs";
|
|
10
|
+
export type { SitepingLogger, SitepingWarnLogger } from "./logger.cjs";
|
|
11
|
+
export { warnSafely } from "./logger.cjs";
|
|
10
12
|
export type { FieldDef, IndexDef, ModelDef, PrismaNativeType, PrismaScalarType, RelationDef, RelationKind, RelationOnDelete, SitepingModelFieldName, SitepingModelName, } from "./schema.cjs";
|
|
11
13
|
export { isRelationField, isScalarField, SITEPING_MODELS } from "./schema.cjs";
|
|
12
14
|
export type { ScreenshotStorage } from "./screenshot-storage.cjs";
|
|
13
15
|
export { SCREENSHOT_DELETE_CONCURRENCY, screenshotMimeType } from "./screenshot-storage.cjs";
|
|
14
16
|
export type { CollectionStore, CollectionStoreBackend } from "./store-helpers.cjs";
|
|
15
17
|
export { buildAnnotationRecord, buildCommentRecord, buildFeedbackRecord, createCollectionStore, } from "./store-helpers.cjs";
|
|
18
|
+
export { REPLACEMENT_CHARACTER, toStorableText, toStorableValue, UNSTORABLE_CODE_UNITS } from "./text.cjs";
|
|
16
19
|
export type { AssertEqual, IfEquals, Prettify, Serialized } from "./type-utils.cjs";
|
|
17
20
|
export { hasOwn, isRecord } from "./type-utils.cjs";
|
|
18
|
-
export type { AnchorData, AnnotationCreateInput, AnnotationPayload, AnnotationRecord, AnnotationResponse, BuiltinLocale, ClosedFeedbackStatus, CommentAuthorRole, CommentCreateInput, CommentDeletePayload, CommentPayload, CommentRecord, CommentResponse, ConsoleDiagnosticEntry, ConsoleDiagnosticLevel, DiagnosticsCaptureOptions, DiagnosticsSnapshot, FeedbackCreateInput, FeedbackCreateOutcome, FeedbackListPermissions, FeedbackPage, FeedbackPayload, FeedbackPermissions, FeedbackQuery, FeedbackRecord, FeedbackResponse, FeedbackResponseList, FeedbackStatus, FeedbackType, FeedbackUpdateInput, NetworkDiagnosticEntry, OpenFeedbackStatus, PageScope, RectData, ScreenshotRegion, SitepingBaseConfig, SitepingCapabilities, SitepingConfig, SitepingDeepLinkOptions, SitepingHeadersOption, SitepingHttpConfig, SitepingIdentity, SitepingInstance, SitepingLocale, SitepingPanelAction, SitepingPanelActionContext, SitepingPanelActionFeedback, SitepingPanelButtonAction, SitepingPanelLinkAction, SitepingPosition, SitepingPublicEventListener, SitepingPublicEvents, SitepingSkipReason, SitepingStore, SitepingStoreConfig, SitepingTheme, SitepingUnsubscribe, } from "./types.cjs";
|
|
19
|
-
export { ANCHOR_ELEMENT_ID_MAX, ANCHOR_ELEMENT_TAG_MAX, BUILTIN_LOCALES, CLOSED_FEEDBACK_STATUSES, COMMENT_AUTHOR_ROLES, COMMENT_BODY_MAX_LENGTH, CONSOLE_DIAGNOSTIC_LEVELS, FEEDBACK_STATUSES, FEEDBACK_TYPES, flattenAnnotation, IDENTITY_FIELD_MAX_LENGTH, isClosedStatus, isStoreDuplicate, isStoreLimit, isStoreNotFound, isStorePersistence, isStoreValueTooLong, MAX_COMMENTS_PER_FEEDBACK, OPEN_FEEDBACK_STATUSES, StoreDuplicateError, StoreLimitError, StoreNotFoundError, StorePersistenceError, StoreValueTooLongError, toFeedbackUpdate, } from "./types.cjs";
|
|
21
|
+
export type { AnchorData, AnnotationCreateInput, AnnotationPayload, AnnotationRecord, AnnotationResponse, BuiltinLocale, ClosedFeedbackStatus, CommentAuthorRole, CommentCreateInput, CommentCreateOutcome, CommentDeletePayload, CommentPayload, CommentPermissions, CommentRecord, CommentResponse, ConsoleDiagnosticEntry, ConsoleDiagnosticLevel, DiagnosticsCaptureOptions, DiagnosticsSnapshot, FeedbackCreateInput, FeedbackCreateOutcome, FeedbackListPermissions, FeedbackPage, FeedbackPayload, FeedbackPermissions, FeedbackQuery, FeedbackRecord, FeedbackResponse, FeedbackResponseList, FeedbackStatus, FeedbackType, FeedbackUpdateInput, NetworkDiagnosticEntry, OpenFeedbackStatus, PageScope, RectData, ScreenshotRegion, SitepingBaseConfig, SitepingCapabilities, SitepingConfig, SitepingDeepLinkOptions, SitepingHeadersOption, SitepingHttpConfig, SitepingIdentity, SitepingInstance, SitepingLocale, SitepingPanelAction, SitepingPanelActionContext, SitepingPanelActionFeedback, SitepingPanelButtonAction, SitepingPanelLinkAction, SitepingPosition, SitepingPublicEventListener, SitepingPublicEvents, SitepingSkipReason, SitepingStore, SitepingStoreConfig, SitepingTheme, SitepingUnsubscribe, } from "./types.cjs";
|
|
22
|
+
export { ANCHOR_ELEMENT_ID_MAX, ANCHOR_ELEMENT_TAG_MAX, BUILTIN_LOCALES, CLIENT_ID_MAX_LENGTH, CLOSED_FEEDBACK_STATUSES, COMMENT_AUTHOR_ROLES, COMMENT_BODY_MAX_LENGTH, CONSOLE_DIAGNOSTIC_LEVELS, FEEDBACK_STATUSES, FEEDBACK_TYPES, flattenAnnotation, IDENTITY_FIELD_MAX_LENGTH, isClosedStatus, isStoreDuplicate, isStoreLimit, isStoreNotFound, isStorePersistence, isStoreValueTooLong, MAX_COMMENTS_PER_FEEDBACK, OPEN_FEEDBACK_STATUSES, PROJECT_NAME_MAX_LENGTH, SITEPING_PROTOCOL_VERSION, StoreDuplicateError, StoreLimitError, StoreNotFoundError, StorePersistenceError, StoreValueTooLongError, toFeedbackUpdate, } from "./types.cjs";
|
|
20
23
|
export { errorFromResponse, feedbackQueryToSearchParams, isCommentGone, isThreadFull, mergeRequestHeaders, networkErrorFromException, newClientId, withSearchParams, } from "./wire.cjs";
|
package/dist/siteping-core.d.ts
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
export { settleWithConcurrencyLimit } from "./concurrency.js";
|
|
2
|
-
export { buildDeepLink, parseHttpUrl } from "./deep-link.js";
|
|
2
|
+
export { buildDeepLink, isSafeImageUrl, parseHttpUrl } from "./deep-link.js";
|
|
3
3
|
export { EMAIL_PATTERN, isValidEmail } from "./email.js";
|
|
4
|
-
export type { SitepingErrorCode } from "./errors.js";
|
|
5
|
-
export { SitepingAuthError, SitepingError, SitepingNetworkError, SitepingValidationError } from "./errors.js";
|
|
4
|
+
export type { SitepingClientError, SitepingConfigErrorCode, SitepingErrorCode } from "./errors.js";
|
|
5
|
+
export { isSitepingConfigError, isSitepingError, SitepingAuthError, SitepingConfigError, SitepingError, SitepingNetworkError, SitepingValidationError, } from "./errors.js";
|
|
6
6
|
export type { FilterResult, Pagination } from "./filters.js";
|
|
7
7
|
export { applyFeedbackFilters, clampPagination, DEFAULT_PAGE_LIMIT, isUnreachableOffset, MAX_PAGE_LIMIT, matchesFeedbackQuery, } from "./filters.js";
|
|
8
8
|
export type { I18n, LocaleLoaders, TranslateFunction } from "./i18n.js";
|
|
9
9
|
export { canonicalizeLocale, createI18n, interpolate, intlLocale, tWithParams } from "./i18n.js";
|
|
10
|
+
export type { SitepingLogger, SitepingWarnLogger } from "./logger.js";
|
|
11
|
+
export { warnSafely } from "./logger.js";
|
|
10
12
|
export type { FieldDef, IndexDef, ModelDef, PrismaNativeType, PrismaScalarType, RelationDef, RelationKind, RelationOnDelete, SitepingModelFieldName, SitepingModelName, } from "./schema.js";
|
|
11
13
|
export { isRelationField, isScalarField, SITEPING_MODELS } from "./schema.js";
|
|
12
14
|
export type { ScreenshotStorage } from "./screenshot-storage.js";
|
|
13
15
|
export { SCREENSHOT_DELETE_CONCURRENCY, screenshotMimeType } from "./screenshot-storage.js";
|
|
14
16
|
export type { CollectionStore, CollectionStoreBackend } from "./store-helpers.js";
|
|
15
17
|
export { buildAnnotationRecord, buildCommentRecord, buildFeedbackRecord, createCollectionStore, } from "./store-helpers.js";
|
|
18
|
+
export { REPLACEMENT_CHARACTER, toStorableText, toStorableValue, UNSTORABLE_CODE_UNITS } from "./text.js";
|
|
16
19
|
export type { AssertEqual, IfEquals, Prettify, Serialized } from "./type-utils.js";
|
|
17
20
|
export { hasOwn, isRecord } from "./type-utils.js";
|
|
18
|
-
export type { AnchorData, AnnotationCreateInput, AnnotationPayload, AnnotationRecord, AnnotationResponse, BuiltinLocale, ClosedFeedbackStatus, CommentAuthorRole, CommentCreateInput, CommentDeletePayload, CommentPayload, CommentRecord, CommentResponse, ConsoleDiagnosticEntry, ConsoleDiagnosticLevel, DiagnosticsCaptureOptions, DiagnosticsSnapshot, FeedbackCreateInput, FeedbackCreateOutcome, FeedbackListPermissions, FeedbackPage, FeedbackPayload, FeedbackPermissions, FeedbackQuery, FeedbackRecord, FeedbackResponse, FeedbackResponseList, FeedbackStatus, FeedbackType, FeedbackUpdateInput, NetworkDiagnosticEntry, OpenFeedbackStatus, PageScope, RectData, ScreenshotRegion, SitepingBaseConfig, SitepingCapabilities, SitepingConfig, SitepingDeepLinkOptions, SitepingHeadersOption, SitepingHttpConfig, SitepingIdentity, SitepingInstance, SitepingLocale, SitepingPanelAction, SitepingPanelActionContext, SitepingPanelActionFeedback, SitepingPanelButtonAction, SitepingPanelLinkAction, SitepingPosition, SitepingPublicEventListener, SitepingPublicEvents, SitepingSkipReason, SitepingStore, SitepingStoreConfig, SitepingTheme, SitepingUnsubscribe, } from "./types.js";
|
|
19
|
-
export { ANCHOR_ELEMENT_ID_MAX, ANCHOR_ELEMENT_TAG_MAX, BUILTIN_LOCALES, CLOSED_FEEDBACK_STATUSES, COMMENT_AUTHOR_ROLES, COMMENT_BODY_MAX_LENGTH, CONSOLE_DIAGNOSTIC_LEVELS, FEEDBACK_STATUSES, FEEDBACK_TYPES, flattenAnnotation, IDENTITY_FIELD_MAX_LENGTH, isClosedStatus, isStoreDuplicate, isStoreLimit, isStoreNotFound, isStorePersistence, isStoreValueTooLong, MAX_COMMENTS_PER_FEEDBACK, OPEN_FEEDBACK_STATUSES, StoreDuplicateError, StoreLimitError, StoreNotFoundError, StorePersistenceError, StoreValueTooLongError, toFeedbackUpdate, } from "./types.js";
|
|
21
|
+
export type { AnchorData, AnnotationCreateInput, AnnotationPayload, AnnotationRecord, AnnotationResponse, BuiltinLocale, ClosedFeedbackStatus, CommentAuthorRole, CommentCreateInput, CommentCreateOutcome, CommentDeletePayload, CommentPayload, CommentPermissions, CommentRecord, CommentResponse, ConsoleDiagnosticEntry, ConsoleDiagnosticLevel, DiagnosticsCaptureOptions, DiagnosticsSnapshot, FeedbackCreateInput, FeedbackCreateOutcome, FeedbackListPermissions, FeedbackPage, FeedbackPayload, FeedbackPermissions, FeedbackQuery, FeedbackRecord, FeedbackResponse, FeedbackResponseList, FeedbackStatus, FeedbackType, FeedbackUpdateInput, NetworkDiagnosticEntry, OpenFeedbackStatus, PageScope, RectData, ScreenshotRegion, SitepingBaseConfig, SitepingCapabilities, SitepingConfig, SitepingDeepLinkOptions, SitepingHeadersOption, SitepingHttpConfig, SitepingIdentity, SitepingInstance, SitepingLocale, SitepingPanelAction, SitepingPanelActionContext, SitepingPanelActionFeedback, SitepingPanelButtonAction, SitepingPanelLinkAction, SitepingPosition, SitepingPublicEventListener, SitepingPublicEvents, SitepingSkipReason, SitepingStore, SitepingStoreConfig, SitepingTheme, SitepingUnsubscribe, } from "./types.js";
|
|
22
|
+
export { ANCHOR_ELEMENT_ID_MAX, ANCHOR_ELEMENT_TAG_MAX, BUILTIN_LOCALES, CLIENT_ID_MAX_LENGTH, CLOSED_FEEDBACK_STATUSES, COMMENT_AUTHOR_ROLES, COMMENT_BODY_MAX_LENGTH, CONSOLE_DIAGNOSTIC_LEVELS, FEEDBACK_STATUSES, FEEDBACK_TYPES, flattenAnnotation, IDENTITY_FIELD_MAX_LENGTH, isClosedStatus, isStoreDuplicate, isStoreLimit, isStoreNotFound, isStorePersistence, isStoreValueTooLong, MAX_COMMENTS_PER_FEEDBACK, OPEN_FEEDBACK_STATUSES, PROJECT_NAME_MAX_LENGTH, SITEPING_PROTOCOL_VERSION, StoreDuplicateError, StoreLimitError, StoreNotFoundError, StorePersistenceError, StoreValueTooLongError, toFeedbackUpdate, } from "./types.js";
|
|
20
23
|
export { errorFromResponse, feedbackQueryToSearchParams, isCommentGone, isThreadFull, mergeRequestHeaders, networkErrorFromException, newClientId, withSearchParams, } from "./wire.js";
|
package/dist/store-helpers.d.cts
CHANGED
|
@@ -69,8 +69,9 @@ export interface CollectionStoreBackend {
|
|
|
69
69
|
/** Generate a unique id for a new feedback, annotation or comment record. */
|
|
70
70
|
generateId(): string;
|
|
71
71
|
/**
|
|
72
|
-
* Keep discussion threads on the records: the store gains `addComment
|
|
73
|
-
* `deleteComment`, and new records start with
|
|
72
|
+
* Keep discussion threads on the records: the store gains `addComment`,
|
|
73
|
+
* `addCommentIfAbsent` and `deleteComment`, and new records start with
|
|
74
|
+
* `comments: []`. Opt in once
|
|
74
75
|
* `load` hands back what `persist` wrote for them, each comment's
|
|
75
76
|
* `createdAt` a `Date` again (a JSON backend revives it like the record's
|
|
76
77
|
* own dates). Off by default, so an adapter written before threads never
|
|
@@ -87,12 +88,14 @@ export type CollectionStore = SitepingStore & Required<Pick<SitepingStore, "veri
|
|
|
87
88
|
/**
|
|
88
89
|
* Build a fully conformant `SitepingStore` on top of a snapshot backend.
|
|
89
90
|
*
|
|
90
|
-
* The engine implements the whole store contract: clientId dedup (
|
|
91
|
-
*
|
|
91
|
+
* The engine implements the whole store contract: clientId dedup (a repeated
|
|
92
|
+
* `clientId` makes `createFeedback` throw `StoreDuplicateError`, and
|
|
93
|
+
* `createFeedbackIfAbsent` report the existing record), newest-first
|
|
92
94
|
* ordering, the standard filter/pagination pipeline, `StoreNotFoundError` on
|
|
93
95
|
* missing update/delete, project-scoped bulk delete,
|
|
94
96
|
* `verifyProjectOwnership`, and — with `comments: true` — discussion threads
|
|
95
|
-
* (`addComment`, `
|
|
97
|
+
* (`addComment`, `addCommentIfAbsent` reporting inserts, `deleteComment`)
|
|
98
|
+
* kept on each record. The snapshot returned by `load` is
|
|
96
99
|
* never mutated: every write hands `persist` a new array, so a failed write leaves
|
|
97
100
|
* a cached snapshot exactly as it was. When `persist` fails during `createFeedback`
|
|
98
101
|
* and the record carries an inline screenshot, the engine retries once
|
|
@@ -101,12 +104,13 @@ export type CollectionStore = SitepingStore & Required<Pick<SitepingStore, "veri
|
|
|
101
104
|
* returning the record would claim a success that was never persisted.
|
|
102
105
|
*
|
|
103
106
|
* Mutations (`createFeedbackIfAbsent`, `createFeedback`, `updateFeedback`,
|
|
104
|
-
* `deleteFeedback`, `deleteAllFeedbacks`, `addComment`, `
|
|
107
|
+
* `deleteFeedback`, `deleteAllFeedbacks`, `addComment`, `addCommentIfAbsent`,
|
|
108
|
+
* `deleteComment`) run
|
|
105
109
|
* one at a time through a queue owned by the returned store, so concurrent
|
|
106
110
|
* calls — the widget's `Promise.all` bulk resolve/delete, a comment posted
|
|
107
111
|
* while its feedback is resolved — never start from the same snapshot and
|
|
108
|
-
* overwrite each other, and `createFeedbackIfAbsent`
|
|
109
|
-
* exactly once per `clientId`. A failed mutation rejects with its own error
|
|
112
|
+
* overwrite each other, and `createFeedbackIfAbsent` and `addCommentIfAbsent`
|
|
113
|
+
* report `created: true` exactly once per `clientId`. A failed mutation rejects with its own error
|
|
110
114
|
* and does not block the ones queued after it, but `load` and `persist` must
|
|
111
115
|
* always settle: one that never does stalls every later mutation on the
|
|
112
116
|
* store, so give network-backed primitives a timeout. Reads are not queued: they see the
|
|
@@ -136,5 +140,5 @@ export type CollectionStore = SitepingStore & Required<Pick<SitepingStore, "veri
|
|
|
136
140
|
*/
|
|
137
141
|
export declare function createCollectionStore(backend: CollectionStoreBackend & {
|
|
138
142
|
comments: true;
|
|
139
|
-
}): CollectionStore & Required<Pick<SitepingStore, "createFeedbackIfAbsent" | "addComment" | "deleteComment">>;
|
|
143
|
+
}): CollectionStore & Required<Pick<SitepingStore, "createFeedbackIfAbsent" | "addComment" | "addCommentIfAbsent" | "deleteComment">>;
|
|
140
144
|
export declare function createCollectionStore(backend: CollectionStoreBackend): CollectionStore & Required<Pick<SitepingStore, "createFeedbackIfAbsent">>;
|