@chidchanun/bcp 0.1.18 → 0.1.20

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.
@@ -608,9 +608,9 @@ if (!globalThis.__BCP_HMR_SOURCE__) {
608
608
  runtimeOutput,
609
609
 
610
610
  content:
611
- fs.readFileSync(
612
- runtimeOutput
613
- ),
611
+ fs.readFileSync(
612
+ runtimeOutput
613
+ ),
614
614
 
615
615
  contentType:
616
616
  "text/javascript; charset=utf-8",
@@ -1114,7 +1114,7 @@ export class DevClientBundler {
1114
1114
  /*
1115
1115
  * =================================
1116
1116
  * Module Graph
1117
- * =================================
1117
+ * =====================================
1118
1118
  */
1119
1119
 
1120
1120
  private rebuildModuleGraph() {
@@ -1155,7 +1155,7 @@ export class DevClientBundler {
1155
1155
  /*
1156
1156
  * =================================
1157
1157
  * Find Affected Routes
1158
- * =================================
1158
+ * =====================================
1159
1159
  */
1160
1160
 
1161
1161
  findAffectedRoutes(
@@ -1201,7 +1201,7 @@ export class DevClientBundler {
1201
1201
  /*
1202
1202
  * =================================
1203
1203
  * Debug Graph
1204
- * =================================
1204
+ * =====================================
1205
1205
  */
1206
1206
 
1207
1207
  printAffectedRoutes(
@@ -1243,7 +1243,7 @@ export class DevClientBundler {
1243
1243
  /*
1244
1244
  * =================================
1245
1245
  * Bundles
1246
- * =================================
1246
+ * =====================================
1247
1247
  */
1248
1248
 
1249
1249
  getBundles():
@@ -1259,7 +1259,7 @@ export class DevClientBundler {
1259
1259
  /*
1260
1260
  * =================================
1261
1261
  * Dispose
1262
- * =================================
1262
+ * =====================================
1263
1263
  */
1264
1264
 
1265
1265
  async dispose() {
@@ -1649,6 +1649,15 @@ function createReactVendorPlugin():
1649
1649
  };
1650
1650
  }
1651
1651
 
1652
+ export function normalizeSourceLineEndings(
1653
+ source: string
1654
+ ): string {
1655
+ return source.replace(
1656
+ /\r\n?/g,
1657
+ "\n"
1658
+ );
1659
+ }
1660
+
1652
1661
  /*
1653
1662
  * =====================================
1654
1663
  * React Refresh Plugin
@@ -1711,11 +1720,13 @@ function createReactRefreshPlugin(
1711
1720
  }
1712
1721
 
1713
1722
  const source =
1714
- await fs.promises
1715
- .readFile(
1716
- args.path,
1717
- "utf8"
1718
- );
1723
+ normalizeSourceLineEndings(
1724
+ await fs.promises
1725
+ .readFile(
1726
+ args.path,
1727
+ "utf8"
1728
+ )
1729
+ );
1719
1730
 
1720
1731
  const extension =
1721
1732
  path.extname(
@@ -0,0 +1,516 @@
1
+ export interface HttpErrorOptions {
2
+ code?: string;
3
+ message?: string;
4
+ details?: unknown;
5
+ headers?: HeadersInit;
6
+ }
7
+
8
+ export interface HttpErrorPayload {
9
+ error: {
10
+ status: number;
11
+ code: string;
12
+ message: string;
13
+ details?: unknown;
14
+ };
15
+ }
16
+
17
+ export interface HttpErrorLike {
18
+ name: string;
19
+ status: number;
20
+ code: string;
21
+ message: string;
22
+ details?: unknown;
23
+ headers?: unknown;
24
+ }
25
+
26
+ export class HttpError
27
+ extends Error {
28
+ readonly status: number;
29
+ readonly code: string;
30
+ readonly details: unknown;
31
+ readonly headers: Headers;
32
+
33
+ constructor(
34
+ status: number,
35
+ options: HttpErrorOptions = {}
36
+ ) {
37
+ assertHttpErrorStatus(
38
+ status
39
+ );
40
+
41
+ const defaults =
42
+ getHttpErrorDefaults(
43
+ status
44
+ );
45
+
46
+ super(
47
+ options.message ??
48
+ defaults.message
49
+ );
50
+
51
+ this.name =
52
+ "HttpError";
53
+ this.status =
54
+ status;
55
+ this.code =
56
+ normalizeErrorCode(
57
+ options.code ??
58
+ defaults.code
59
+ );
60
+ this.details =
61
+ options.details;
62
+ this.headers =
63
+ new Headers(
64
+ options.headers
65
+ );
66
+ }
67
+ }
68
+
69
+ export function createHttpError(
70
+ status: number,
71
+ options: HttpErrorOptions = {}
72
+ ): HttpError {
73
+ return new HttpError(
74
+ status,
75
+ options
76
+ );
77
+ }
78
+
79
+ export function throwHttpError(
80
+ status: number,
81
+ options: HttpErrorOptions = {}
82
+ ): never {
83
+ throw createHttpError(
84
+ status,
85
+ options
86
+ );
87
+ }
88
+
89
+ export function isHttpError(
90
+ error: unknown
91
+ ): error is HttpErrorLike {
92
+ return (
93
+ error instanceof
94
+ HttpError ||
95
+ (
96
+ typeof error ===
97
+ "object" &&
98
+ error !== null &&
99
+ "name" in error &&
100
+ error.name ===
101
+ "HttpError" &&
102
+ "status" in error &&
103
+ typeof error.status ===
104
+ "number" &&
105
+ Number.isInteger(
106
+ error.status
107
+ ) &&
108
+ error.status >= 400 &&
109
+ error.status <= 599 &&
110
+ "code" in error &&
111
+ typeof error.code ===
112
+ "string" &&
113
+ "message" in error &&
114
+ typeof error.message ===
115
+ "string"
116
+ )
117
+ );
118
+ }
119
+
120
+ export function toErrorResponse(
121
+ error: unknown,
122
+ fallback: HttpErrorOptions = {}
123
+ ): Response {
124
+ const httpError =
125
+ isHttpError(
126
+ error
127
+ )
128
+ ? normalizeHttpError(
129
+ error
130
+ )
131
+ : createHttpError(
132
+ 500,
133
+ fallback
134
+ );
135
+
136
+ return createHttpErrorResponse(
137
+ httpError
138
+ );
139
+ }
140
+
141
+ export function errorResponse(
142
+ status: number,
143
+ options: HttpErrorOptions = {}
144
+ ): Response {
145
+ return createHttpErrorResponse(
146
+ createHttpError(
147
+ status,
148
+ options
149
+ )
150
+ );
151
+ }
152
+
153
+ export function badRequest(
154
+ message = "Bad Request",
155
+ details?: unknown
156
+ ): Response {
157
+ return errorResponse(
158
+ 400,
159
+ {
160
+ code:
161
+ "bad_request",
162
+ message,
163
+ details,
164
+ }
165
+ );
166
+ }
167
+
168
+ export function unauthorized(
169
+ message = "Unauthorized",
170
+ details?: unknown
171
+ ): Response {
172
+ return errorResponse(
173
+ 401,
174
+ {
175
+ code:
176
+ "unauthorized",
177
+ message,
178
+ details,
179
+ }
180
+ );
181
+ }
182
+
183
+ export function forbidden(
184
+ message = "Forbidden",
185
+ details?: unknown
186
+ ): Response {
187
+ return errorResponse(
188
+ 403,
189
+ {
190
+ code:
191
+ "forbidden",
192
+ message,
193
+ details,
194
+ }
195
+ );
196
+ }
197
+
198
+ export function notFoundResponse(
199
+ message = "Not Found",
200
+ details?: unknown
201
+ ): Response {
202
+ return errorResponse(
203
+ 404,
204
+ {
205
+ code:
206
+ "not_found",
207
+ message,
208
+ details,
209
+ }
210
+ );
211
+ }
212
+
213
+ export function conflict(
214
+ message = "Conflict",
215
+ details?: unknown
216
+ ): Response {
217
+ return errorResponse(
218
+ 409,
219
+ {
220
+ code:
221
+ "conflict",
222
+ message,
223
+ details,
224
+ }
225
+ );
226
+ }
227
+
228
+ export function unprocessableEntity(
229
+ message = "Unprocessable Entity",
230
+ details?: unknown
231
+ ): Response {
232
+ return errorResponse(
233
+ 422,
234
+ {
235
+ code:
236
+ "unprocessable_entity",
237
+ message,
238
+ details,
239
+ }
240
+ );
241
+ }
242
+
243
+ export function tooManyRequests(
244
+ message = "Too Many Requests",
245
+ options: {
246
+ details?: unknown;
247
+ retryAfter?:
248
+ | number
249
+ | string;
250
+ } = {}
251
+ ): Response {
252
+ const headers =
253
+ new Headers();
254
+
255
+ if (
256
+ options.retryAfter !==
257
+ undefined
258
+ ) {
259
+ headers.set(
260
+ "Retry-After",
261
+ String(
262
+ options.retryAfter
263
+ )
264
+ );
265
+ }
266
+
267
+ return errorResponse(
268
+ 429,
269
+ {
270
+ code:
271
+ "too_many_requests",
272
+ message,
273
+ details:
274
+ options.details,
275
+ headers,
276
+ }
277
+ );
278
+ }
279
+
280
+ export function internalServerError(
281
+ message = "Internal Server Error"
282
+ ): Response {
283
+ return errorResponse(
284
+ 500,
285
+ {
286
+ code:
287
+ "internal_server_error",
288
+ message,
289
+ }
290
+ );
291
+ }
292
+
293
+ export function serviceUnavailable(
294
+ message = "Service Unavailable",
295
+ details?: unknown
296
+ ): Response {
297
+ return errorResponse(
298
+ 503,
299
+ {
300
+ code:
301
+ "service_unavailable",
302
+ message,
303
+ details,
304
+ }
305
+ );
306
+ }
307
+
308
+ function createHttpErrorResponse(
309
+ error: HttpError
310
+ ): Response {
311
+ const payload:
312
+ HttpErrorPayload = {
313
+ error: {
314
+ status:
315
+ error.status,
316
+ code:
317
+ error.code,
318
+ message:
319
+ error.message,
320
+ },
321
+ };
322
+
323
+ if (
324
+ error.details !==
325
+ undefined
326
+ ) {
327
+ payload.error.details =
328
+ error.details;
329
+ }
330
+
331
+ const headers =
332
+ new Headers(
333
+ error.headers
334
+ );
335
+
336
+ if (
337
+ !headers.has(
338
+ "Cache-Control"
339
+ )
340
+ ) {
341
+ headers.set(
342
+ "Cache-Control",
343
+ "no-store"
344
+ );
345
+ }
346
+
347
+ return Response.json(
348
+ payload,
349
+ {
350
+ status:
351
+ error.status,
352
+ headers,
353
+ }
354
+ );
355
+ }
356
+
357
+ function normalizeHttpError(
358
+ error: HttpErrorLike
359
+ ): HttpError {
360
+ if (
361
+ error instanceof
362
+ HttpError
363
+ ) {
364
+ return error;
365
+ }
366
+
367
+ return createHttpError(
368
+ error.status,
369
+ {
370
+ code:
371
+ error.code,
372
+ message:
373
+ error.message,
374
+ details:
375
+ error.details,
376
+ headers:
377
+ error.headers instanceof
378
+ Headers
379
+ ? error.headers
380
+ : undefined,
381
+ }
382
+ );
383
+ }
384
+
385
+ function assertHttpErrorStatus(
386
+ status: number
387
+ ): void {
388
+ if (
389
+ !Number.isInteger(
390
+ status
391
+ ) ||
392
+ status < 400 ||
393
+ status > 599
394
+ ) {
395
+ throw new RangeError(
396
+ `BCP Framework: HTTP error status must be an integer from 400 to 599, received ${status}.`
397
+ );
398
+ }
399
+ }
400
+
401
+ function normalizeErrorCode(
402
+ value: string
403
+ ): string {
404
+ const normalized =
405
+ value
406
+ .trim()
407
+ .toLowerCase()
408
+ .replace(
409
+ /[^a-z0-9]+/g,
410
+ "_"
411
+ )
412
+ .replace(
413
+ /^_+|_+$/g,
414
+ ""
415
+ );
416
+
417
+ if (!normalized) {
418
+ throw new Error(
419
+ "BCP Framework: HTTP error code must not be empty."
420
+ );
421
+ }
422
+
423
+ return normalized;
424
+ }
425
+
426
+ function getHttpErrorDefaults(
427
+ status: number
428
+ ): {
429
+ code: string;
430
+ message: string;
431
+ } {
432
+ switch (status) {
433
+ case 400:
434
+ return {
435
+ code: "bad_request",
436
+ message: "Bad Request",
437
+ };
438
+ case 401:
439
+ return {
440
+ code: "unauthorized",
441
+ message: "Unauthorized",
442
+ };
443
+ case 403:
444
+ return {
445
+ code: "forbidden",
446
+ message: "Forbidden",
447
+ };
448
+ case 404:
449
+ return {
450
+ code: "not_found",
451
+ message: "Not Found",
452
+ };
453
+ case 405:
454
+ return {
455
+ code: "method_not_allowed",
456
+ message: "Method Not Allowed",
457
+ };
458
+ case 409:
459
+ return {
460
+ code: "conflict",
461
+ message: "Conflict",
462
+ };
463
+ case 413:
464
+ return {
465
+ code: "payload_too_large",
466
+ message: "Payload Too Large",
467
+ };
468
+ case 415:
469
+ return {
470
+ code: "unsupported_media_type",
471
+ message: "Unsupported Media Type",
472
+ };
473
+ case 422:
474
+ return {
475
+ code: "unprocessable_entity",
476
+ message: "Unprocessable Entity",
477
+ };
478
+ case 429:
479
+ return {
480
+ code: "too_many_requests",
481
+ message: "Too Many Requests",
482
+ };
483
+ case 500:
484
+ return {
485
+ code: "internal_server_error",
486
+ message: "Internal Server Error",
487
+ };
488
+ case 501:
489
+ return {
490
+ code: "not_implemented",
491
+ message: "Not Implemented",
492
+ };
493
+ case 502:
494
+ return {
495
+ code: "bad_gateway",
496
+ message: "Bad Gateway",
497
+ };
498
+ case 503:
499
+ return {
500
+ code: "service_unavailable",
501
+ message: "Service Unavailable",
502
+ };
503
+ case 504:
504
+ return {
505
+ code: "gateway_timeout",
506
+ message: "Gateway Timeout",
507
+ };
508
+ default:
509
+ return {
510
+ code:
511
+ `http_${status}`,
512
+ message:
513
+ `HTTP ${status}`,
514
+ };
515
+ }
516
+ }
@@ -22,6 +22,28 @@ export {
22
22
  type RedirectStatus,
23
23
  } from "../../server/src/server-response.js";
24
24
 
25
+ export {
26
+ badRequest,
27
+ conflict,
28
+ createHttpError,
29
+ errorResponse,
30
+ forbidden,
31
+ HttpError,
32
+ internalServerError,
33
+ isHttpError,
34
+ notFoundResponse,
35
+ serviceUnavailable,
36
+ throwHttpError,
37
+ tooManyRequests,
38
+ toErrorResponse,
39
+ unauthorized,
40
+ unprocessableEntity,
41
+
42
+ type HttpErrorLike,
43
+ type HttpErrorOptions,
44
+ type HttpErrorPayload,
45
+ } from "./http-error.js";
46
+
25
47
  export {
26
48
  createSession,
27
49
  createSessionToken,