webpack-dev-server 5.1.0 → 5.2.1

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/lib/Server.js CHANGED
@@ -307,6 +307,8 @@ function useFn(route, fn) {
307
307
  return /** @type {BasicApplication} */ ({});
308
308
  }
309
309
 
310
+ const DEFAULT_ALLOWED_PROTOCOLS = /^(file|.+-extension):/i;
311
+
310
312
  /**
311
313
  * @typedef {Object} BasicApplication
312
314
  * @property {typeof useFn} use
@@ -404,6 +406,7 @@ class Server {
404
406
  let host;
405
407
 
406
408
  const networks = Object.values(os.networkInterfaces())
409
+ // eslint-disable-next-line no-shadow
407
410
  .flatMap((networks) => networks ?? [])
408
411
  .filter((network) => {
409
412
  if (!network || !network.address) {
@@ -436,8 +439,9 @@ class Server {
436
439
  return network.address;
437
440
  });
438
441
 
439
- for (const network of networks) {
440
- host = network.address;
442
+ if (networks.length > 0) {
443
+ // Take the first network found
444
+ host = networks[0].address;
441
445
 
442
446
  if (host.includes(":")) {
443
447
  host = `[${host}]`;
@@ -793,15 +797,12 @@ class Server {
793
797
  webSocketURLStr = searchParams.toString();
794
798
  }
795
799
 
796
- additionalEntries.push(
797
- `${require.resolve("../client/index.js")}?${webSocketURLStr}`,
798
- );
800
+ additionalEntries.push(`${this.getClientEntry()}?${webSocketURLStr}`);
799
801
  }
800
802
 
801
- if (this.options.hot === "only") {
802
- additionalEntries.push(require.resolve("webpack/hot/only-dev-server"));
803
- } else if (this.options.hot) {
804
- additionalEntries.push(require.resolve("webpack/hot/dev-server"));
803
+ const clientHotEntry = this.getClientHotEntry();
804
+ if (clientHotEntry) {
805
+ additionalEntries.push(clientHotEntry);
805
806
  }
806
807
 
807
808
  const webpack = compiler.webpack || require("webpack");
@@ -1676,6 +1677,25 @@ class Server {
1676
1677
  return implementation;
1677
1678
  }
1678
1679
 
1680
+ /**
1681
+ * @returns {string}
1682
+ */
1683
+ // eslint-disable-next-line class-methods-use-this
1684
+ getClientEntry() {
1685
+ return require.resolve("../client/index.js");
1686
+ }
1687
+
1688
+ /**
1689
+ * @returns {string | void}
1690
+ */
1691
+ getClientHotEntry() {
1692
+ if (this.options.hot === "only") {
1693
+ return require.resolve("webpack/hot/only-dev-server");
1694
+ } else if (this.options.hot) {
1695
+ return require.resolve("webpack/hot/dev-server");
1696
+ }
1697
+ }
1698
+
1679
1699
  /**
1680
1700
  * @private
1681
1701
  * @returns {void}
@@ -1943,7 +1963,7 @@ class Server {
1943
1963
  (req.headers);
1944
1964
  const headerName = headers[":authority"] ? ":authority" : "host";
1945
1965
 
1946
- if (this.checkHeader(headers, headerName)) {
1966
+ if (this.isValidHost(headers, headerName)) {
1947
1967
  next();
1948
1968
  return;
1949
1969
  }
@@ -1953,6 +1973,32 @@ class Server {
1953
1973
  },
1954
1974
  });
1955
1975
 
1976
+ // Register setup cross origin request check for security
1977
+ middlewares.push({
1978
+ name: "cross-origin-header-check",
1979
+ /**
1980
+ * @param {Request} req
1981
+ * @param {Response} res
1982
+ * @param {NextFunction} next
1983
+ * @returns {void}
1984
+ */
1985
+ middleware: (req, res, next) => {
1986
+ const headers =
1987
+ /** @type {{ [key: string]: string | undefined }} */
1988
+ (req.headers);
1989
+ if (
1990
+ headers["sec-fetch-mode"] === "no-cors" &&
1991
+ headers["sec-fetch-site"] === "cross-site"
1992
+ ) {
1993
+ res.statusCode = 403;
1994
+ res.end("Cross-Origin request blocked");
1995
+ return;
1996
+ }
1997
+
1998
+ next();
1999
+ },
2000
+ });
2001
+
1956
2002
  const isHTTP2 =
1957
2003
  /** @type {ServerConfiguration<A, S>} */ (this.options.server).type ===
1958
2004
  "http2";
@@ -2624,8 +2670,9 @@ class Server {
2624
2670
 
2625
2671
  if (
2626
2672
  !headers ||
2627
- !this.checkHeader(headers, "host") ||
2628
- !this.checkHeader(headers, "origin")
2673
+ !this.isValidHost(headers, "host") ||
2674
+ !this.isValidHost(headers, "origin") ||
2675
+ !this.isSameOrigin(headers)
2629
2676
  ) {
2630
2677
  this.sendMessage([client], "error", "Invalid Host/Origin header");
2631
2678
 
@@ -2659,7 +2706,8 @@ class Server {
2659
2706
 
2660
2707
  if (
2661
2708
  this.options.client &&
2662
- /** @type {ClientConfiguration} */ (this.options.client).reconnect
2709
+ /** @type {ClientConfiguration} */
2710
+ (this.options.client).reconnect
2663
2711
  ) {
2664
2712
  this.sendMessage(
2665
2713
  [client],
@@ -2674,9 +2722,9 @@ class Server {
2674
2722
  /** @type {ClientConfiguration} */
2675
2723
  (this.options.client).overlay
2676
2724
  ) {
2677
- const overlayConfig = /** @type {ClientConfiguration} */ (
2678
- this.options.client
2679
- ).overlay;
2725
+ const overlayConfig =
2726
+ /** @type {ClientConfiguration} */
2727
+ (this.options.client).overlay;
2680
2728
 
2681
2729
  this.sendMessage(
2682
2730
  [client],
@@ -3062,40 +3110,105 @@ class Server {
3062
3110
 
3063
3111
  /**
3064
3112
  * @private
3065
- * @param {{ [key: string]: string | undefined }} headers
3066
- * @param {string} headerToCheck
3113
+ * @param {string} value
3067
3114
  * @returns {boolean}
3068
3115
  */
3069
- checkHeader(headers, headerToCheck) {
3116
+ isHostAllowed(value) {
3117
+ const { allowedHosts } = this.options;
3118
+
3070
3119
  // allow user to opt out of this security check, at their own risk
3071
3120
  // by explicitly enabling allowedHosts
3121
+ if (allowedHosts === "all") {
3122
+ return true;
3123
+ }
3124
+
3125
+ // always allow localhost host, for convenience
3126
+ // allow if value is in allowedHosts
3127
+ if (Array.isArray(allowedHosts) && allowedHosts.length > 0) {
3128
+ for (let hostIdx = 0; hostIdx < allowedHosts.length; hostIdx++) {
3129
+ /** @type {string} */
3130
+ const allowedHost = allowedHosts[hostIdx];
3131
+
3132
+ if (allowedHost === value) {
3133
+ return true;
3134
+ }
3135
+
3136
+ // support "." as a subdomain wildcard
3137
+ // e.g. ".example.com" will allow "example.com", "www.example.com", "subdomain.example.com", etc
3138
+ if (allowedHost[0] === ".") {
3139
+ // "example.com" (value === allowedHost.substring(1))
3140
+ // "*.example.com" (value.endsWith(allowedHost))
3141
+ if (
3142
+ value === allowedHost.substring(1) ||
3143
+ /** @type {string} */
3144
+ (value).endsWith(allowedHost)
3145
+ ) {
3146
+ return true;
3147
+ }
3148
+ }
3149
+ }
3150
+ }
3151
+
3152
+ // Also allow if `client.webSocketURL.hostname` provided
3153
+ if (
3154
+ this.options.client &&
3155
+ typeof (
3156
+ /** @type {ClientConfiguration} */
3157
+ (this.options.client).webSocketURL
3158
+ ) !== "undefined"
3159
+ ) {
3160
+ return (
3161
+ /** @type {WebSocketURL} */
3162
+ (/** @type {ClientConfiguration} */ (this.options.client).webSocketURL)
3163
+ .hostname === value
3164
+ );
3165
+ }
3166
+
3167
+ return false;
3168
+ }
3169
+
3170
+ /**
3171
+ * @private
3172
+ * @param {{ [key: string]: string | undefined }} headers
3173
+ * @param {string} headerToCheck
3174
+ * @returns {boolean}
3175
+ */
3176
+ isValidHost(headers, headerToCheck) {
3072
3177
  if (this.options.allowedHosts === "all") {
3073
3178
  return true;
3074
3179
  }
3075
3180
 
3076
3181
  // get the Host header and extract hostname
3077
3182
  // we don't care about port not matching
3078
- const hostHeader = headers[headerToCheck];
3183
+ const header = headers[headerToCheck];
3079
3184
 
3080
- if (!hostHeader) {
3185
+ if (!header) {
3081
3186
  return false;
3082
3187
  }
3083
3188
 
3084
- if (/^(file|.+-extension):/i.test(hostHeader)) {
3189
+ if (DEFAULT_ALLOWED_PROTOCOLS.test(header)) {
3085
3190
  return true;
3086
3191
  }
3087
3192
 
3088
3193
  // use the node url-parser to retrieve the hostname from the host-header.
3089
3194
  const hostname = url.parse(
3090
- // if hostHeader doesn't have scheme, add // for parsing.
3091
- /^(.+:)?\/\//.test(hostHeader) ? hostHeader : `//${hostHeader}`,
3195
+ // if header doesn't have scheme, add // for parsing.
3196
+ /^(.+:)?\/\//.test(header) ? header : `//${header}`,
3092
3197
  false,
3093
3198
  true,
3094
3199
  ).hostname;
3095
3200
 
3201
+ if (hostname === null) {
3202
+ return false;
3203
+ }
3204
+
3205
+ if (this.isHostAllowed(hostname)) {
3206
+ return true;
3207
+ }
3208
+
3096
3209
  // always allow requests with explicit IPv4 or IPv6-address.
3097
3210
  // A note on IPv6 addresses:
3098
- // hostHeader will always contain the brackets denoting
3211
+ // header will always contain the brackets denoting
3099
3212
  // an IPv6-address in URLs,
3100
3213
  // these are removed from the hostname in url.parse(),
3101
3214
  // so we have the pure IPv6-address in hostname.
@@ -3103,60 +3216,76 @@ class Server {
3103
3216
  // and its subdomains (hostname.endsWith(".localhost")).
3104
3217
  // allow hostname of listening address (hostname === this.options.host)
3105
3218
  const isValidHostname =
3106
- (hostname !== null && ipaddr.IPv4.isValid(hostname)) ||
3107
- (hostname !== null && ipaddr.IPv6.isValid(hostname)) ||
3219
+ ipaddr.IPv4.isValid(hostname) ||
3220
+ ipaddr.IPv6.isValid(hostname) ||
3108
3221
  hostname === "localhost" ||
3109
- (hostname !== null && hostname.endsWith(".localhost")) ||
3222
+ hostname.endsWith(".localhost") ||
3110
3223
  hostname === this.options.host;
3111
3224
 
3112
3225
  if (isValidHostname) {
3113
3226
  return true;
3114
3227
  }
3115
3228
 
3116
- const { allowedHosts } = this.options;
3229
+ // disallow
3230
+ return false;
3231
+ }
3117
3232
 
3118
- // always allow localhost host, for convenience
3119
- // allow if hostname is in allowedHosts
3120
- if (Array.isArray(allowedHosts) && allowedHosts.length > 0) {
3121
- for (let hostIdx = 0; hostIdx < allowedHosts.length; hostIdx++) {
3122
- /** @type {string} */
3123
- const allowedHost = allowedHosts[hostIdx];
3233
+ /**
3234
+ * @private
3235
+ * @param {{ [key: string]: string | undefined }} headers
3236
+ * @returns {boolean}
3237
+ */
3238
+ isSameOrigin(headers) {
3239
+ if (this.options.allowedHosts === "all") {
3240
+ return true;
3241
+ }
3124
3242
 
3125
- if (allowedHost === hostname) {
3126
- return true;
3127
- }
3243
+ const originHeader = headers.origin;
3128
3244
 
3129
- // support "." as a subdomain wildcard
3130
- // e.g. ".example.com" will allow "example.com", "www.example.com", "subdomain.example.com", etc
3131
- if (allowedHost[0] === ".") {
3132
- // "example.com" (hostname === allowedHost.substring(1))
3133
- // "*.example.com" (hostname.endsWith(allowedHost))
3134
- if (
3135
- hostname === allowedHost.substring(1) ||
3136
- /** @type {string} */ (hostname).endsWith(allowedHost)
3137
- ) {
3138
- return true;
3139
- }
3140
- }
3141
- }
3245
+ if (!originHeader) {
3246
+ return this.options.allowedHosts === "all";
3142
3247
  }
3143
3248
 
3144
- // Also allow if `client.webSocketURL.hostname` provided
3145
- if (
3146
- this.options.client &&
3147
- typeof (
3148
- /** @type {ClientConfiguration} */ (this.options.client).webSocketURL
3149
- ) !== "undefined"
3150
- ) {
3151
- return (
3152
- /** @type {WebSocketURL} */
3153
- (/** @type {ClientConfiguration} */ (this.options.client).webSocketURL)
3154
- .hostname === hostname
3155
- );
3249
+ if (DEFAULT_ALLOWED_PROTOCOLS.test(originHeader)) {
3250
+ return true;
3156
3251
  }
3157
3252
 
3158
- // disallow
3159
- return false;
3253
+ const origin = url.parse(originHeader, false, true).hostname;
3254
+
3255
+ if (origin === null) {
3256
+ return false;
3257
+ }
3258
+
3259
+ if (this.isHostAllowed(origin)) {
3260
+ return true;
3261
+ }
3262
+
3263
+ const hostHeader = headers.host;
3264
+
3265
+ if (!hostHeader) {
3266
+ return this.options.allowedHosts === "all";
3267
+ }
3268
+
3269
+ if (DEFAULT_ALLOWED_PROTOCOLS.test(hostHeader)) {
3270
+ return true;
3271
+ }
3272
+
3273
+ const host = url.parse(
3274
+ // if hostHeader doesn't have scheme, add // for parsing.
3275
+ /^(.+:)?\/\//.test(hostHeader) ? hostHeader : `//${hostHeader}`,
3276
+ false,
3277
+ true,
3278
+ ).hostname;
3279
+
3280
+ if (host === null) {
3281
+ return false;
3282
+ }
3283
+
3284
+ if (this.isHostAllowed(host)) {
3285
+ return true;
3286
+ }
3287
+
3288
+ return origin === host;
3160
3289
  }
3161
3290
 
3162
3291
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webpack-dev-server",
3
- "version": "5.1.0",
3
+ "version": "5.2.1",
4
4
  "description": "Serves a webpack app. Updates the browser on changes.",
5
5
  "bin": "bin/webpack-dev-server.js",
6
6
  "main": "lib/Server.js",
@@ -49,6 +49,7 @@
49
49
  "@types/bonjour": "^3.5.13",
50
50
  "@types/connect-history-api-fallback": "^1.5.4",
51
51
  "@types/express": "^4.17.21",
52
+ "@types/express-serve-static-core": "^4.17.21",
52
53
  "@types/serve-index": "^1.9.4",
53
54
  "@types/serve-static": "^1.15.5",
54
55
  "@types/sockjs": "^0.3.36",
@@ -59,10 +60,9 @@
59
60
  "colorette": "^2.0.10",
60
61
  "compression": "^1.7.4",
61
62
  "connect-history-api-fallback": "^2.0.0",
62
- "express": "^4.19.2",
63
+ "express": "^4.21.2",
63
64
  "graceful-fs": "^4.2.6",
64
- "html-entities": "^2.4.0",
65
- "http-proxy-middleware": "^2.0.3",
65
+ "http-proxy-middleware": "^2.0.7",
66
66
  "ipaddr.js": "^2.1.0",
67
67
  "launch-editor": "^2.6.1",
68
68
  "open": "^10.0.3",
@@ -76,38 +76,38 @@
76
76
  "ws": "^8.18.0"
77
77
  },
78
78
  "devDependencies": {
79
- "@babel/cli": "^7.25.6",
80
- "@babel/core": "^7.25.2",
81
- "@babel/eslint-parser": "^7.25.1",
82
- "@babel/plugin-transform-object-assign": "^7.24.7",
83
- "@babel/plugin-transform-runtime": "^7.25.4",
84
- "@babel/preset-env": "^7.25.4",
85
- "@babel/runtime": "^7.25.6",
86
- "@commitlint/cli": "^19.4.1",
87
- "@commitlint/config-conventional": "^19.4.1",
88
- "@hono/node-server": "^1.12.2",
79
+ "@babel/cli": "^7.25.9",
80
+ "@babel/core": "^7.25.9",
81
+ "@babel/eslint-parser": "^7.25.9",
82
+ "@babel/plugin-transform-object-assign": "^7.25.9",
83
+ "@babel/plugin-transform-runtime": "^7.25.9",
84
+ "@babel/preset-env": "^7.25.9",
85
+ "@babel/runtime": "^7.25.9",
86
+ "@commitlint/cli": "^19.5.0",
87
+ "@commitlint/config-conventional": "^19.5.0",
88
+ "@hono/node-server": "^1.13.3",
89
89
  "@types/compression": "^1.7.2",
90
- "@types/node": "^22.5.2",
90
+ "@types/node": "^22.8.4",
91
91
  "@types/node-forge": "^1.3.1",
92
92
  "@types/sockjs-client": "^1.5.1",
93
93
  "@types/trusted-types": "^2.0.2",
94
- "acorn": "^8.9.0",
94
+ "acorn": "^8.14.0",
95
95
  "babel-jest": "^29.5.0",
96
- "babel-loader": "^9.1.0",
96
+ "babel-loader": "^9.2.1",
97
97
  "body-parser": "^1.19.2",
98
98
  "connect": "^3.7.0",
99
99
  "core-js": "^3.38.1",
100
- "cspell": "^8.14.2",
100
+ "cspell": "^8.15.5",
101
101
  "css-loader": "^7.1.1",
102
- "eslint": "^8.43.0",
102
+ "eslint": "^8.57.1",
103
103
  "eslint-config-prettier": "^9.1.0",
104
104
  "eslint-config-webpack": "^1.2.5",
105
- "eslint-plugin-import": "^2.30.0",
105
+ "eslint-plugin-import": "^2.31.0",
106
106
  "execa": "^5.1.1",
107
- "hono": "^4.5.11",
108
- "html-webpack-plugin": "^5.5.3",
107
+ "hono": "^4.6.8",
108
+ "html-webpack-plugin": "^5.6.3",
109
109
  "http-proxy": "^1.18.1",
110
- "husky": "^9.1.5",
110
+ "husky": "^9.1.6",
111
111
  "jest": "^29.5.0",
112
112
  "jest-environment-jsdom": "^29.5.0",
113
113
  "klona": "^2.0.4",
@@ -115,10 +115,10 @@
115
115
  "less-loader": "^12.1.0",
116
116
  "lint-staged": "^15.2.10",
117
117
  "marked": "^12.0.0",
118
- "memfs": "^4.6.0",
118
+ "memfs": "^4.14.0",
119
119
  "npm-run-all": "^4.1.5",
120
120
  "prettier": "^3.2.4",
121
- "puppeteer": "^23.2.2",
121
+ "puppeteer": "^23.6.1",
122
122
  "readable-stream": "^4.5.2",
123
123
  "require-from-string": "^2.0.2",
124
124
  "rimraf": "^5.0.5",
@@ -128,7 +128,7 @@
128
128
  "style-loader": "^4.0.0",
129
129
  "supertest": "^7.0.0",
130
130
  "tcp-port-used": "^1.0.2",
131
- "typescript": "^5.5.4",
131
+ "typescript": "^5.7.2",
132
132
  "wait-for-expect": "^3.0.2",
133
133
  "webpack": "^5.94.0",
134
134
  "webpack-cli": "^5.0.1",
@@ -1134,7 +1134,7 @@ declare class Server<
1134
1134
  */
1135
1135
  static findIp(
1136
1136
  gatewayOrFamily: string,
1137
- isInternal?: boolean | undefined,
1137
+ isInternal?: boolean,
1138
1138
  ): string | undefined;
1139
1139
  /**
1140
1140
  * @param {"v4" | "v6"} family
@@ -1230,6 +1230,14 @@ declare class Server<
1230
1230
  * @returns {T}
1231
1231
  */
1232
1232
  private getServerTransport;
1233
+ /**
1234
+ * @returns {string}
1235
+ */
1236
+ getClientEntry(): string;
1237
+ /**
1238
+ * @returns {string | void}
1239
+ */
1240
+ getClientHotEntry(): string | void;
1233
1241
  /**
1234
1242
  * @private
1235
1243
  * @returns {void}
@@ -1339,13 +1347,25 @@ declare class Server<
1339
1347
  * @param {NextFunction} next
1340
1348
  */
1341
1349
  private setHeaders;
1350
+ /**
1351
+ * @private
1352
+ * @param {string} value
1353
+ * @returns {boolean}
1354
+ */
1355
+ private isHostAllowed;
1342
1356
  /**
1343
1357
  * @private
1344
1358
  * @param {{ [key: string]: string | undefined }} headers
1345
1359
  * @param {string} headerToCheck
1346
1360
  * @returns {boolean}
1347
1361
  */
1348
- private checkHeader;
1362
+ private isValidHost;
1363
+ /**
1364
+ * @private
1365
+ * @param {{ [key: string]: string | undefined }} headers
1366
+ * @returns {boolean}
1367
+ */
1368
+ private isSameOrigin;
1349
1369
  /**
1350
1370
  * @param {ClientConnection[]} clients
1351
1371
  * @param {string} type
@@ -1369,16 +1389,11 @@ declare class Server<
1369
1389
  * @param {string | string[]} watchPath
1370
1390
  * @param {WatchOptions} [watchOptions]
1371
1391
  */
1372
- watchFiles(
1373
- watchPath: string | string[],
1374
- watchOptions?: import("chokidar").WatchOptions | undefined,
1375
- ): void;
1392
+ watchFiles(watchPath: string | string[], watchOptions?: WatchOptions): void;
1376
1393
  /**
1377
1394
  * @param {import("webpack-dev-middleware").Callback} [callback]
1378
1395
  */
1379
- invalidate(
1380
- callback?: import("webpack-dev-middleware").Callback | undefined,
1381
- ): void;
1396
+ invalidate(callback?: import("webpack-dev-middleware").Callback): void;
1382
1397
  /**
1383
1398
  * @returns {Promise<void>}
1384
1399
  */
@@ -1386,7 +1401,7 @@ declare class Server<
1386
1401
  /**
1387
1402
  * @param {(err?: Error) => void} [callback]
1388
1403
  */
1389
- startCallback(callback?: ((err?: Error) => void) | undefined): void;
1404
+ startCallback(callback?: (err?: Error) => void): void;
1390
1405
  /**
1391
1406
  * @returns {Promise<void>}
1392
1407
  */
@@ -1394,7 +1409,7 @@ declare class Server<
1394
1409
  /**
1395
1410
  * @param {(err?: Error) => void} [callback]
1396
1411
  */
1397
- stopCallback(callback?: ((err?: Error) => void) | undefined): void;
1412
+ stopCallback(callback?: (err?: Error) => void): void;
1398
1413
  }
1399
1414
  declare namespace Server {
1400
1415
  export {
@@ -1,64 +0,0 @@
1
- function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
2
- function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
3
- function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
4
- function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
5
- function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
6
- /**
7
- * @typedef {Object} StateDefinitions
8
- * @property {{[event: string]: { target: string; actions?: Array<string> }}} [on]
9
- */
10
-
11
- /**
12
- * @typedef {Object} Options
13
- * @property {{[state: string]: StateDefinitions}} states
14
- * @property {object} context;
15
- * @property {string} initial
16
- */
17
-
18
- /**
19
- * @typedef {Object} Implementation
20
- * @property {{[actionName: string]: (ctx: object, event: any) => object}} actions
21
- */
22
-
23
- /**
24
- * A simplified `createMachine` from `@xstate/fsm` with the following differences:
25
- *
26
- * - the returned machine is technically a "service". No `interpret(machine).start()` is needed.
27
- * - the state definition only support `on` and target must be declared with { target: 'nextState', actions: [] } explicitly.
28
- * - event passed to `send` must be an object with `type` property.
29
- * - actions implementation will be [assign action](https://xstate.js.org/docs/guides/context.html#assign-action) if you return any value.
30
- * Do not return anything if you just want to invoke side effect.
31
- *
32
- * The goal of this custom function is to avoid installing the entire `'xstate/fsm'` package, while enabling modeling using
33
- * state machine. You can copy the first parameter into the editor at https://stately.ai/viz to visualize the state machine.
34
- *
35
- * @param {Options} options
36
- * @param {Implementation} implementation
37
- */
38
- function createMachine(_ref, _ref2) {
39
- var states = _ref.states,
40
- context = _ref.context,
41
- initial = _ref.initial;
42
- var actions = _ref2.actions;
43
- var currentState = initial;
44
- var currentContext = context;
45
- return {
46
- send: function send(event) {
47
- var currentStateOn = states[currentState].on;
48
- var transitionConfig = currentStateOn && currentStateOn[event.type];
49
- if (transitionConfig) {
50
- currentState = transitionConfig.target;
51
- if (transitionConfig.actions) {
52
- transitionConfig.actions.forEach(function (actName) {
53
- var actionImpl = actions[actName];
54
- var nextContextValue = actionImpl && actionImpl(currentContext, event);
55
- if (nextContextValue) {
56
- currentContext = _objectSpread(_objectSpread({}, currentContext), nextContextValue);
57
- }
58
- });
59
- }
60
- }
61
- }
62
- };
63
- }
64
- export default createMachine;
@@ -1,47 +0,0 @@
1
- /**
2
- *
3
- * @param {Error} error
4
- */
5
- function parseErrorToStacks(error) {
6
- if (!error || !(error instanceof Error)) {
7
- throw new Error("parseErrorToStacks expects Error object");
8
- }
9
- if (typeof error.stack === "string") {
10
- return error.stack.split("\n").filter(function (stack) {
11
- return stack !== "Error: ".concat(error.message);
12
- });
13
- }
14
- }
15
-
16
- /**
17
- * @callback ErrorCallback
18
- * @param {ErrorEvent} error
19
- * @returns {void}
20
- */
21
-
22
- /**
23
- * @param {ErrorCallback} callback
24
- */
25
- function listenToRuntimeError(callback) {
26
- window.addEventListener("error", callback);
27
- return function cleanup() {
28
- window.removeEventListener("error", callback);
29
- };
30
- }
31
-
32
- /**
33
- * @callback UnhandledRejectionCallback
34
- * @param {PromiseRejectionEvent} rejectionEvent
35
- * @returns {void}
36
- */
37
-
38
- /**
39
- * @param {UnhandledRejectionCallback} callback
40
- */
41
- function listenToUnhandledRejection(callback) {
42
- window.addEventListener("unhandledrejection", callback);
43
- return function cleanup() {
44
- window.removeEventListener("unhandledrejection", callback);
45
- };
46
- }
47
- export { listenToRuntimeError, listenToUnhandledRejection, parseErrorToStacks };